This document contains the networking specification for Ethereum 2.0 clients.
It consists of four main sections:
StrictNoSign
signature policy?message-id
?MAXIMUM_GOSSIP_CLOCK_DISPARITY
when validating slot ranges of messages in gossip subnets?ATTESTATION_SUBNET_COUNT
attestation subnets?SLOTS_PER_EPOCH
slots?AggregateAndProof
s rather than just as Attestation
s?BeaconBlocksByRange
let the server choose which branch to send blocks from?This section outlines the specification for the networking stack in Ethereum 2.0 clients.
Even though libp2p is a multi-transport stack (designed to listen on multiple simultaneous transports and endpoints transparently), we hereby define a profile for basic interoperability.
All implementations MUST support the TCP libp2p transport, and it MUST be enabled for both dialing and listening (i.e. outbound and inbound connections). The libp2p TCP transport supports listening on IPv4 and IPv6 addresses (and on multiple simultaneously).
Clients must support listening on at least one of IPv4 or IPv6. Clients that do not have support for listening on IPv4 SHOULD be cognizant of the potential disadvantages in terms of Internet-wide routability/support. Clients MAY choose to listen only on IPv6, but MUST be capable of dialing both IPv4 and IPv6 addresses.
All listening endpoints must be publicly dialable, and thus not rely on libp2p circuit relay, AutoNAT, or AutoRelay facilities. (Usage of circuit relay, AutoNAT, or AutoRelay will be specifically re-examined soon.)
Nodes operating behind a NAT, or otherwise undialable by default (e.g. container runtime, firewall, etc.), MUST have their infrastructure configured to enable inbound traffic on the announced public listening endpoint.
The Libp2p-noise secure
channel handshake with secp256k1
identities will be used for encryption.
As specified in the libp2p specification, clients MUST support the XX
handshake pattern.
Clients MUST use exact equality when negotiating protocol versions to use and MAY use the version to give priority to higher version numbers.
Clients MUST support multistream-select 1.0 and MAY support multiselect 2.0 when the spec solidifies. Once all clients have implementations for multiselect 2.0, multistream-select 1.0 MAY be phased out.
During connection bootstrapping, libp2p dynamically negotiates a mutually supported multiplexing method to conduct parallel conversations. This applies to transports that are natively incapable of multiplexing (e.g. TCP, WebSockets, WebRTC), and is omitted for capable transports (e.g. QUIC).
Two multiplexers are commonplace in libp2p implementations:
mplex and yamux.
Their protocol IDs are, respectively: /mplex/6.7.0
and /yamux/1.0.0
.
Clients MUST support mplex and MAY support yamux. If both are supported by the client, yamux MUST take precedence during negotiation. See the Rationale section below for tradeoffs.
This section outlines constants that are used in this spec.
| Name | Value | Description |
|---|---|---|
GOSSIP_MAX_SIZE |
2**20 (= 1048576, 1 MiB) |
The maximum allowed size of uncompressed gossip messages. |
MAX_REQUEST_BLOCKS |
2**10 (= 1024) |
Maximum number of blocks in a single request |
MAX_CHUNK_SIZE |
2**20 (1048576, 1 MiB) |
The maximum allowed size of uncompressed req/resp chunked responses. |
TTFB_TIMEOUT |
5s |
The maximum time to wait for first byte of request response (time-to-first-byte). |
RESP_TIMEOUT |
10s |
The maximum time for complete response transfer. |
ATTESTATION_PROPAGATION_SLOT_RANGE |
32 |
The maximum number of slots during which an attestation can be propagated. |
MAXIMUM_GOSSIP_CLOCK_DISPARITY |
500ms |
The maximum milliseconds of clock disparity assumed between honest nodes. |
MESSAGE_DOMAIN_INVALID_SNAPPY |
0x00000000 |
4-byte domain for gossip message-id isolation of invalid snappy messages |
MESSAGE_DOMAIN_VALID_SNAPPY |
0x01000000 |
4-byte domain for gossip message-id isolation of valid snappy messages |
Clients MUST locally store the following MetaData
:
(
seq_number: uint64
attnets: Bitvector[ATTESTATION_SUBNET_COUNT]
)
Where
seq_number
is a uint64
starting at 0
used to version the node’s metadata.
If any other field in the local MetaData
changes, the node MUST increment seq_number
by 1.attnets
is a Bitvector
representing the node’s persistent attestation subnet subscriptions.Note: MetaData.seq_number
is used for versioning of the node’s metadata,
is entirely independent of the ENR sequence number,
and will in most cases be out of sync with the ENR sequence number.
Clients MUST support the gossipsub v1 libp2p Protocol including the gossipsub v1.1 extension.
Protocol ID: /meshsub/1.1.0
Gossipsub Parameters
The following gossipsub parameters will be used:
D
(topic stable mesh target count): 8D_low
(topic stable mesh low watermark): 6D_high
(topic stable mesh high watermark): 12D_lazy
(gossip target): 6heartbeat_interval
(frequency of heartbeat, seconds): 0.7fanout_ttl
(ttl for fanout maps for topics we are not subscribed to but have published to, seconds): 60mcache_len
(number of windows to retain full messages in cache for IWANT
responses): 6mcache_gossip
(number of windows to gossip about): 3seen_ttl
(number of heartbeat intervals to retain message IDs): 550Note: Gossipsub v1.1 introduces a number of additional parameters for peer scoring and other attack mitigations. These are currently under investigation and will be spec’d and released to mainnet when they are ready.
Topics are plain UTF-8 strings and are encoded on the wire as determined by protobuf (gossipsub messages are enveloped in protobuf messages).
Topic strings have form: /eth2/ForkDigestValue/Name/Encoding
.
This defines both the type of data being sent on the topic and how the data field of the message is encoded.
ForkDigestValue
- the lowercase hex-encoded (no “0x” prefix) bytes of compute_fork_digest(current_fork_version, genesis_validators_root)
where
current_fork_version
is the fork version of the epoch of the message to be sent on the topicgenesis_validators_root
is the static Root
found in state.genesis_validators_root
Name
- see table belowEncoding
- the encoding strategy describes a specific representation of bytes that will be transmitted over the wire.
See the Encodings section for further details.Note: ForkDigestValue
is composed of values that are not known until the genesis block/state are available.
Due to this, clients SHOULD NOT subscribe to gossipsub topics until these genesis values are known.
Each gossipsub message has a maximum size of GOSSIP_MAX_SIZE
.
Clients MUST reject (fail validation) messages that are over this size limit.
Likewise, clients MUST NOT emit or propagate messages larger than this limit.
The optional from
(1), seqno
(3), signature
(5) and key
(6) protobuf fields are omitted from the message,
since messages are identified by content, anonymous, and signed where necessary in the application layer.
Starting from Gossipsub v1.1, clients MUST enforce this by applying the StrictNoSign
signature policy.
The message-id
of a gossipsub message MUST be the following 20 byte value computed from the message data:
message.data
has a valid snappy decompression, set message-id
to the first 20 bytes of the SHA256
hash of
the concatenation of MESSAGE_DOMAIN_VALID_SNAPPY
with the snappy decompressed message data,
i.e. SHA256(MESSAGE_DOMAIN_VALID_SNAPPY + snappy_decompress(message.data))[:20]
.message-id
to the first 20 bytes of the SHA256
hash of
the concatenation of MESSAGE_DOMAIN_INVALID_SNAPPY
with the raw message data,
i.e. SHA256(MESSAGE_DOMAIN_INVALID_SNAPPY + message.data)[:20]
.Note: The above logic handles two exceptional cases:
(1) multiple snappy data
can decompress to the same value,
and (2) some message data
can fail to snappy decompress altogether.
The payload is carried in the data
field of a gossipsub message, and varies depending on the topic:
| Name | Message Type |
|---|---|
beacon_block |
SignedBeaconBlock |
beacon_aggregate_and_proof |
SignedAggregateAndProof |
beacon_attestation_{subnet_id} |
Attestation |
voluntary_exit |
SignedVoluntaryExit |
proposer_slashing |
ProposerSlashing |
attester_slashing |
AttesterSlashing |
Clients MUST reject (fail validation) messages containing an incorrect type, or invalid payload.
When processing incoming gossip, clients MAY descore or disconnect peers who fail to observe these constraints.
For any optional queueing, clients SHOULD maintain maximum queue sizes to avoid DoS vectors.
Gossipsub v1.1 introduces Extended Validators
for the application to aid in the gossipsub peer-scoring scheme.
We utilize ACCEPT
, REJECT
, and IGNORE
. For each gossipsub topic, there are application specific validations.
If all validations pass, return ACCEPT
.
If one or more validations fail while processing the items in order, return either REJECT
or IGNORE
as specified in the prefix of the particular condition.
There are two primary global topics used to propagate beacon blocks (beacon_block
)
and aggregate attestations (beacon_aggregate_and_proof
) to all nodes on the network.
There are three additional global topics are used to propagate lower frequency validator messages
(voluntary_exit
, proposer_slashing
, and attester_slashing
).
beacon_block
The beacon_block
topic is used solely for propagating new signed beacon blocks to all nodes on the networks.
Signed blocks are sent in their entirety.
The following validations MUST pass before forwarding the signed_beacon_block
on the network.
MAXIMUM_GOSSIP_CLOCK_DISPARITY
allowance) –
i.e. validate that signed_beacon_block.message.slot <= current_slot
(a client MAY queue future blocks for processing at the appropriate slot).signed_beacon_block.message.slot > compute_start_slot_at_epoch(state.finalized_checkpoint.epoch)
(a client MAY choose to validate and store such blocks for additional purposes – e.g. slashing detection, archive nodes, etc).signed_beacon_block.message.slot
.signed_beacon_block.signature
, is valid with respect to the proposer_index
pubkey.block.parent_root
) has been seen
(via both gossip and non-gossip sources)
(a client MAY queue blocks for processing once the parent block is retrieved).block.parent_root
) passes validation.finalized_checkpoint
is an ancestor of block
– i.e.
get_ancestor(store, block.parent_root, compute_start_slot_at_epoch(store.finalized_checkpoint.epoch))
== store.finalized_checkpoint.root
proposer_index
for the block’s slot
in the context of the current shuffling (defined by parent_root
/slot
).
If the proposer_index
cannot immediately be verified against the expected shuffling,
the block MAY be queued for later processing while proposers for the block’s branch are calculated –
in such a case do not REJECT
, instead IGNORE
this message.beacon_aggregate_and_proof
The beacon_aggregate_and_proof
topic is used to propagate aggregated attestations (as SignedAggregateAndProof
s)
to subscribing nodes (typically validators) to be included in future blocks.
The following validations MUST pass before forwarding the signed_aggregate_and_proof
on the network.
(We define the following for convenience – aggregate_and_proof = signed_aggregate_and_proof.message
and aggregate = aggregate_and_proof.aggregate
)
aggregate.data.slot
is within the last ATTESTATION_PROPAGATION_SLOT_RANGE
slots (with a MAXIMUM_GOSSIP_CLOCK_DISPARITY
allowance) –
i.e. aggregate.data.slot + ATTESTATION_PROPAGATION_SLOT_RANGE >= current_slot >= aggregate.data.slot
(a client MAY queue future aggregates for processing at the appropriate slot).aggregate.data.target.epoch ==
compute_epoch_at_slot(aggregate.data.slot)
hash_tree_root(aggregate)
has not already been seen
(via aggregate gossip, within a verified block, or through the creation of an equivalent aggregate locally).aggregate
is the first valid aggregate received for the aggregator
with index aggregate_and_proof.aggregator_index
for the epoch aggregate.data.target.epoch
.len(get_attesting_indices(state, aggregate.data, aggregate.aggregation_bits)) >= 1
.aggregate_and_proof.selection_proof
selects the validator as an aggregator for the slot –
i.e. is_aggregator(state, aggregate.data.slot, aggregate.data.index, aggregate_and_proof.selection_proof)
returns True
.aggregate_and_proof.aggregator_index in get_beacon_committee(state, aggregate.data.slot, aggregate.data.index)
.aggregate_and_proof.selection_proof
is a valid signature
of the aggregate.data.slot
by the validator with index aggregate_and_proof.aggregator_index
.signed_aggregate_and_proof.signature
, is valid.aggregate
is valid.aggregate.data.beacon_block_root
) has been seen
(via both gossip and non-gossip sources)
(a client MAY queue aggregates for processing once block is retrieved).aggregate.data.beacon_block_root
) passes validation.finalized_checkpoint
is an ancestor of the block
defined by aggregate.data.beacon_block_root
– i.e.
get_ancestor(store, aggregate.data.beacon_block_root, compute_start_slot_at_epoch(store.finalized_checkpoint.epoch))
== store.finalized_checkpoint.root
voluntary_exit
The voluntary_exit
topic is used solely for propagating signed voluntary validator exits to proposers on the network.
Signed voluntary exits are sent in their entirety.
The following validations MUST pass before forwarding the signed_voluntary_exit
on to the network.
signed_voluntary_exit.message.validator_index
.process_voluntary_exit
pass validation.proposer_slashing
The proposer_slashing
topic is used solely for propagating proposer slashings to proposers on the network.
Proposer slashings are sent in their entirety.
The following validations MUST pass before forwarding the proposer_slashing
on to the network.
proposer_slashing.signed_header_1.message.proposer_index
.process_proposer_slashing
pass validation.attester_slashing
The attester_slashing
topic is used solely for propagating attester slashings to proposers on the network.
Attester slashings are sent in their entirety.
Clients who receive an attester slashing on this topic MUST validate the conditions within process_attester_slashing
before forwarding it across the network.
attester_slashing
(i.e. attester_slashed_indices = set(attestation_1.attesting_indices).intersection(attestation_2.attesting_indices)
,
verify if any(attester_slashed_indices.difference(prior_seen_attester_slashed_indices))
).process_attester_slashing
pass validation.Attestation subnets are used to propagate unaggregated attestations to subsections of the network.
beacon_attestation_{subnet_id}
The beacon_attestation_{subnet_id}
topics are used to propagate unaggregated attestations
to the subnet subnet_id
(typically beacon and persistent committees) to be aggregated before being gossiped to beacon_aggregate_and_proof
.
The following validations MUST pass before forwarding the attestation
on the subnet.
data.index < get_committee_count_per_slot(state, data.target.epoch)
.compute_subnet_for_attestation(committees_per_slot, attestation.data.slot, attestation.data.index) == subnet_id
,
where committees_per_slot = get_committee_count_per_slot(state, attestation.data.target.epoch)
,
which may be pre-computed along with the committee information for the signature check.attestation.data.slot
is within the last ATTESTATION_PROPAGATION_SLOT_RANGE
slots
(within a MAXIMUM_GOSSIP_CLOCK_DISPARITY
allowance) –
i.e. attestation.data.slot + ATTESTATION_PROPAGATION_SLOT_RANGE >= current_slot >= attestation.data.slot
(a client MAY queue future attestations for processing at the appropriate slot).attestation.data.target.epoch ==
compute_epoch_at_slot(attestation.data.slot)
len([bit for bit in attestation.aggregation_bits if bit]) == 1
, i.e. exactly 1 bit is set).len(attestation.aggregation_bits) == len(get_beacon_committee(state, data.slot, data.index))
.attestation.data.target.epoch
and participating validator index.attestation
is valid.attestation.data.beacon_block_root
) has been seen
(via both gossip and non-gossip sources)
(a client MAY queue attestations for processing once block is retrieved).attestation.data.beacon_block_root
) passes validation.get_ancestor(store, attestation.data.beacon_block_root, compute_start_slot_at_epoch(attestation.data.target.epoch)) == attestation.data.target.root
finalized_checkpoint
is an ancestor of the block
defined by attestation.data.beacon_block_root
– i.e.
get_ancestor(store, attestation.data.beacon_block_root, compute_start_slot_at_epoch(store.finalized_checkpoint.epoch))
== store.finalized_checkpoint.root
Attestation broadcasting is grouped into subnets defined by a topic.
The number of subnets is defined via ATTESTATION_SUBNET_COUNT
.
The correct subnet for an attestation can be calculated with compute_subnet_for_attestation
.
beacon_attestation_{subnet_id}
topics, are rotated through throughout the epoch in a similar fashion to rotating through shards in committees in Phase 1.
The subnets are rotated through with committees_per_slot = get_committee_count_per_slot(state, attestation.data.target.epoch)
subnets per slot.
Unaggregated attestations are sent as Attestation
s to the subnet topic,
beacon_attestation_{compute_subnet_for_attestation(committees_per_slot, attestation.data.slot, attestation.data.index)}
as Attestation
s.
Aggregated attestations are sent to the beacon_aggregate_and_proof
topic as AggregateAndProof
s.
Topics are post-fixed with an encoding. Encodings define how the payload of a gossipsub message is encoded.
ssz_snappy
- All objects are SSZ-encoded and then compressed with Snappy block compression.
Example: The beacon aggregate attestation topic string is /eth2/446a7232/beacon_aggregate_and_proof/ssz_snappy
,
the fork digest is 446a7232
and the data field of a gossipsub message is an AggregateAndProof
that has been SSZ-encoded and then compressed with Snappy.Snappy has two formats: “block” and “frames” (streaming). Gossip messages remain relatively small (100s of bytes to 100s of kilobytes) so basic snappy block compression is used to avoid the additional overhead associated with snappy frames.
Implementations MUST use a single encoding for gossip. Changing an encoding will require coordination between participating implementations.
Each message type is segregated into its own libp2p protocol ID, which is a case-sensitive UTF-8 string of the form:
/ProtocolPrefix/MessageName/SchemaVersion/Encoding
With:
ProtocolPrefix
- messages are grouped into families identified by a shared libp2p protocol name prefix.
In this case, we use /eth2/beacon_chain/req
.MessageName
- each request is identified by a name consisting of English alphabet, digits and underscores (_
).SchemaVersion
- an ordinal version number (e.g. 1, 2, 3…).
Each schema is versioned to facilitate backward and forward-compatibility when possible.Encoding
- while the schema defines the data types in more abstract terms,
the encoding strategy describes a specific representation of bytes that will be transmitted over the wire.
See the Encodings section for further details.This protocol segregation allows libp2p multistream-select 1.0
/ multiselect 2.0
to handle the request type, version, and encoding negotiation before establishing the underlying streams.
We use ONE stream PER request/response interaction. Streams are closed when the interaction finishes, whether in success or in error.
Request/response messages MUST adhere to the encoding specified in the protocol name and follow this structure (relaxed BNF grammar):
request ::= <encoding-dependent-header> | <encoded-payload>
response ::= <response_chunk>*
response_chunk ::= <result> | <encoding-dependent-header> | <encoded-payload>
result ::= “0” | “1” | “2” | [“128” ... ”255”]
The encoding-dependent header may carry metadata or assertions such as the encoded payload length, for integrity and attack proofing purposes. Because req/resp streams are single-use and stream closures implicitly delimit the boundaries, it is not strictly necessary to length-prefix payloads; however, certain encodings like SSZ do, for added security.
A response
is formed by zero or more response_chunk
s.
Responses that consist of a single SSZ-list (such as BlocksByRange
and BlocksByRoot
) send each list item as a response_chunk
.
All other response types (non-Lists) send a single response_chunk
.
For both request
s and response
s, the encoding-dependent-header
MUST be valid,
and the encoded-payload
must be valid within the constraints of the encoding-dependent-header
.
This includes type-specific bounds on payload size for some encoding strategies.
Regardless of these type specific bounds, a global maximum uncompressed byte size of MAX_CHUNK_SIZE
MUST be applied to all method response chunks.
Clients MUST ensure that lengths are within these bounds; if not, they SHOULD reset the stream immediately. Clients tracking peer reputation MAY decrement the score of the misbehaving peer under this circumstance.
Once a new stream with the protocol ID for the request type has been negotiated, the full request message SHOULD be sent immediately. The request MUST be encoded according to the encoding strategy.
The requester MUST close the write side of the stream once it finishes writing the request message. At this point, the stream will be half-closed.
The requester MUST wait a maximum of TTFB_TIMEOUT
for the first response byte to arrive (time to first byte—or TTFB—timeout).
On that happening, the requester allows a further RESP_TIMEOUT
for each subsequent response_chunk
received.
If any of these timeouts fire, the requester SHOULD reset the stream and deem the req/resp operation to have failed.
A requester SHOULD read from the stream until either:
response_chunk
fails validation.For requests consisting of a single valid response_chunk
,
the requester SHOULD read the chunk fully, as defined by the encoding-dependent-header
, before closing the stream.
Once a new stream with the protocol ID for the request type has been negotiated, the responder SHOULD process the incoming request and MUST validate it before processing it. Request processing and validation MUST be done according to the encoding strategy, until EOF (denoting stream half-closure by the requester).
The responder MUST:
N
, it should read exactly N
bytes from the stream, at which point an EOF should arise (no more bytes).
Should this not be the case, it should be treated as a failure.response_chunk
s (result, optional header, payload).If steps (1), (2), or (3) fail due to invalid, malformed, or inconsistent data, the responder MUST respond in error. Clients tracking peer reputation MAY record such failures, as well as unexpected events, e.g. early stream resets.
The entire request should be read in no more than RESP_TIMEOUT
.
Upon a timeout, the responder SHOULD reset the stream.
The responder SHOULD send a response_chunk
promptly.
Chunks start with a single-byte response code which determines the contents of the response_chunk
(result
particle in the BNF grammar above).
For multiple chunks, only the last chunk is allowed to have a non-zero error code (i.e. The chunk stream is terminated once an error occurs).
The response code can have one of the following values, encoded as a single unsigned byte:
ErrorMessage
schema (described below).ErrorMessage
schema (described below).Clients MAY use response codes above 128
to indicate alternative, erroneous request-specific responses.
The range [3, 127]
is RESERVED for future usages, and should be treated as error if not recognized expressly.
The ErrorMessage
schema is:
(
error_message: List[byte, 256]
)
Note: By convention, the error_message
is a sequence of bytes that MAY be interpreted as a UTF-8 string (for debugging purposes).
Clients MUST treat as valid any byte sequences.
The token of the negotiated protocol ID specifies the type of encoding to be used for the req/resp interaction. Only one value is possible at this time:
ssz_snappy
: The contents are first SSZ-encoded
and then compressed with Snappy frames compression.
For objects containing a single field, only the field is SSZ-encoded not a container with a single field.
For example, the BeaconBlocksByRoot
request is an SSZ-encoded list of Root
’s.
This encoding type MUST be supported by all clients.The SimpleSerialize (SSZ) specification outlines how objects are SSZ-encoded.
To achieve snappy encoding on top of SSZ, we feed the serialized form of the object to the Snappy compressor on encoding. The inverse happens on decoding.
Snappy has two formats: “block” and “frames” (streaming). To support large requests and response chunks, snappy-framing is used.
Since snappy frame contents have a maximum size of 65536
bytes
and frame headers are just identifier (1) + checksum (4)
bytes, the expected buffering of a single frame is acceptable.
Encoding-dependent header: Req/Resp protocols using the ssz_snappy
encoding strategy MUST encode the length of the raw SSZ bytes,
encoded as an unsigned protobuf varint.
Writing: By first computing and writing the SSZ byte length, the SSZ encoder can then directly write the chunk contents to the stream. When Snappy is applied, it can be passed through a buffered Snappy writer to compress frame by frame.
Reading: After reading the expected SSZ byte length, the SSZ decoder can directly read the contents from the stream. When snappy is applied, it can be passed through a buffered Snappy reader to decompress frame by frame.
Before reading the payload, the header MUST be validated:
uint64
.After reading a valid header, the payload MAY be read, while maintaining the size constraints from the header.
A reader SHOULD NOT read more than max_encoded_len(n)
bytes after reading the SSZ length-prefix n
from the header.
ssz_snappy
this is: 32 + n + n // 6
.
This is considered the worst-case compression result by Snappy.A reader SHOULD consider the following cases as invalid input:
n
SSZ bytes. An EOF is expected if more bytes are read than required.In case of an invalid input (header or payload), a reader MUST:
InvalidRequest
. The request itself is ignored.All messages that contain only a single field MUST be encoded directly as the type of that field and MUST NOT be encoded as an SSZ container.
Responses that are SSZ-lists (for example List[SignedBeaconBlock, ...]
) send their
constituents individually as response_chunk
s. For example, the
List[SignedBeaconBlock, ...]
response type sends zero or more response_chunk
s.
Each successful response_chunk
contains a single SignedBeaconBlock
payload.
Protocol ID: /eth2/beacon_chain/req/status/1/
Request, Response Content:
(
fork_digest: ForkDigest
finalized_root: Root
finalized_epoch: Epoch
head_root: Root
head_slot: Slot
)
The fields are, as seen by the client at the time of sending the message:
fork_digest
: The node’s ForkDigest
(compute_fork_digest(current_fork_version, genesis_validators_root)
) where
current_fork_version
is the fork version at the node’s current epoch defined by the wall-clock time
(not necessarily the epoch to which the node is sync)genesis_validators_root
is the static Root
found in state.genesis_validators_root
finalized_root
: state.finalized_checkpoint.root
for the state corresponding to the head block
(Note this defaults to Root(b'\x00' * 32)
for the genesis finalized checkpoint).finalized_epoch
: state.finalized_checkpoint.epoch
for the state corresponding to the head block.head_root
: The hash_tree_root
root of the current head block (BeaconBlock
).head_slot
: The slot of the block corresponding to the head_root
.The dialing client MUST send a Status
request upon connection.
The request/response MUST be encoded as an SSZ-container.
The response MUST consist of a single response_chunk
.
Clients SHOULD immediately disconnect from one another following the handshake above under the following conditions:
fork_digest
does not match the node’s local fork_digest
, since the client’s chain is on another fork.finalized_root
, finalized_epoch
) shared by the peer is not in the client’s chain at the expected epoch.
For example, if Peer 1 sends (root, epoch) of (A, 5) and Peer 2 sends (B, 3) but Peer 1 has root C at epoch 3,
then Peer 1 would disconnect because it knows that their chains are irreparably disjoint.Once the handshake completes, the client with the lower finalized_epoch
or head_slot
(if the clients have equal finalized_epoch
s)
SHOULD request beacon blocks from its counterparty via the BeaconBlocksByRange
request.
Note: Under abnormal network condition or after some rounds of BeaconBlocksByRange
requests,
the client might need to send Status
request again to learn if the peer has a higher head.
Implementers are free to implement such behavior in their own way.
Protocol ID: /eth2/beacon_chain/req/goodbye/1/
Request, Response Content:
(
uint64
)
Client MAY send goodbye messages upon disconnection. The reason field MAY be one of the following values:
Clients MAY use reason codes above 128
to indicate alternative, erroneous request-specific responses.
The range [4, 127]
is RESERVED for future usage.
The request/response MUST be encoded as a single SSZ-field.
The response MUST consist of a single response_chunk
.
Protocol ID: /eth2/beacon_chain/req/beacon_blocks_by_range/1/
Request Content:
(
start_slot: Slot
count: uint64
step: uint64
)
Response Content:
(
List[SignedBeaconBlock, MAX_REQUEST_BLOCKS]
)
Requests beacon blocks in the slot range [start_slot, start_slot + count * step)
, leading up to the current head block as selected by fork choice.
step
defines the slot increment between blocks.
For example, requesting blocks starting at start_slot
2 with a step value of 2 would return the blocks at slots [2, 4, 6, …].
In cases where a slot is empty for a given slot number, no block is returned.
For example, if slot 4 were empty in the previous example, the returned array would contain [2, 6, …].
A request MUST NOT have a 0 slot increment, i.e. step >= 1
.
BeaconBlocksByRange
is primarily used to sync historical blocks.
The request MUST be encoded as an SSZ-container.
The response MUST consist of zero or more response_chunk
.
Each successful response_chunk
MUST contain a single SignedBeaconBlock
payload.
Clients MUST keep a record of signed blocks seen since the start of the weak subjectivity period
and MUST support serving requests of blocks up to their own head_block_root
.
Clients MUST respond with at least the first block that exists in the range, if they have it, and no more than MAX_REQUEST_BLOCKS
blocks.
The following blocks, where they exist, MUST be sent in consecutive order.
Clients MAY limit the number of blocks in the response.
The response MUST contain no more than count
blocks.
Clients MUST respond with blocks from their view of the current fork choice
– that is, blocks from the single chain defined by the current head.
Of note, blocks from slots before the finalization MUST lead to the finalized block reported in the Status
handshake.
Clients MUST respond with blocks that are consistent from a single chain within the context of the request.
This applies to any step
value.
In particular when step == 1
, each parent_root
MUST match the hash_tree_root
of the preceding block.
After the initial block, clients MAY stop in the process of responding if their fork choice changes the view of the chain in the context of the request.
Protocol ID: /eth2/beacon_chain/req/beacon_blocks_by_root/1/
Request Content:
(
List[Root, MAX_REQUEST_BLOCKS]
)
Response Content:
(
List[SignedBeaconBlock, MAX_REQUEST_BLOCKS]
)
Requests blocks by block root (= hash_tree_root(SignedBeaconBlock.message)
).
The response is a list of SignedBeaconBlock
whose length is less than or equal to the number of requested blocks.
It may be less in the case that the responding peer is missing blocks.
No more than MAX_REQUEST_BLOCKS
may be requested at a time.
BeaconBlocksByRoot
is primarily used to recover recent blocks (e.g. when receiving a block or attestation whose parent is unknown).
The request MUST be encoded as an SSZ-field.
The response MUST consist of zero or more response_chunk
.
Each successful response_chunk
MUST contain a single SignedBeaconBlock
payload.
Clients MUST support requesting blocks since the latest finalized epoch.
Clients MUST respond with at least one block, if they have it. Clients MAY limit the number of blocks in the response.
Protocol ID: /eth2/beacon_chain/req/ping/1/
Request Content:
(
uint64
)
Response Content:
(
uint64
)
Sent intermittently, the Ping
protocol checks liveness of connected peers.
Peers request and respond with their local metadata sequence number (MetaData.seq_number
).
If the peer does not respond to the Ping
request, the client MAY disconnect from the peer.
A client can then determine if their local record of a peer’s MetaData is up to date
and MAY request an updated version via the MetaData
RPC method if not.
The request MUST be encoded as an SSZ-field.
The response MUST consist of a single response_chunk
.
Protocol ID: /eth2/beacon_chain/req/metadata/1/
No Request Content.
Response Content:
(
MetaData
)
Requests the MetaData of a peer. The request opens and negotiates the stream without sending any request content. Once established the receiving peer responds with it’s local most up-to-date MetaData.
The response MUST be encoded as an SSZ-container.
The response MUST consist of a single response_chunk
.
Discovery Version 5 (discv5) (Protocol version v5.1) is used for peer discovery.
discv5
is a standalone protocol, running on UDP on a dedicated port, meant for peer discovery only.
discv5
supports self-certified, flexible peer records (ENRs) and topic-based advertisement, both of which are (or will be) requirements in this context.
discv5
SHOULD be integrated into the client’s libp2p stack by implementing an adaptor
to make it conform to the service discovery
and peer routing abstractions and interfaces (go-libp2p links provided).
Inputs to operations include peer IDs (when locating a specific peer) or capabilities (when searching for peers with a specific capability), and the outputs will be multiaddrs converted from the ENR records returned by the discv5 backend.
This integration enables the libp2p stack to subsequently form connections and streams with discovered peers.
The Ethereum Node Record (ENR) for an Ethereum 2.0 client MUST contain the following entries (exclusive of the sequence number and signature, which MUST be present in an ENR):
secp256k1
field).The ENR MAY contain the following entries:
ip
field) and/or IPv6 address (ip6
field).tcp
field) representing the local libp2p listening port.udp
field) representing the local discv5 listening port.Specifications of these parameters can be found in the ENR Specification.
The ENR attnets
entry signifies the attestation subnet bitfield with the following form
to more easily discover peers participating in particular attestation gossip subnets.
| Key | Value |
|---|---|
attnets |
SSZ Bitvector[ATTESTATION_SUBNET_COUNT] |
If a node’s MetaData.attnets
has any non-zero bit, the ENR MUST include the attnets
entry with the same value as MetaData.attnets
.
If a node’s MetaData.attnets
is composed of all zeros, the ENR MAY optionally include the attnets
entry or leave it out entirely.
eth2
fieldENRs MUST carry a generic eth2
key with an 16-byte value of the node’s current fork digest, next fork version,
and next fork epoch to ensure connections are made with peers on the intended eth2 network.
| Key | Value |
|---|---|
eth2 |
SSZ ENRForkID |
Specifically, the value of the eth2
key MUST be the following SSZ encoded object (ENRForkID
)
(
fork_digest: ForkDigest
next_fork_version: Version
next_fork_epoch: Epoch
)
where the fields of ENRForkID
are defined as
fork_digest
is compute_fork_digest(current_fork_version, genesis_validators_root)
where
current_fork_version
is the fork version at the node’s current epoch defined by the wall-clock time
(not necessarily the epoch to which the node is sync)genesis_validators_root
is the static Root
found in state.genesis_validators_root
next_fork_version
is the fork version corresponding to the next planned hard fork at a future epoch.
If no future fork is planned, set next_fork_version = current_fork_version
to signal this factnext_fork_epoch
is the epoch at which the next fork is planned and the current_fork_version
will be updated.
If no future fork is planned, set next_fork_epoch = FAR_FUTURE_EPOCH
to signal this factNote: fork_digest
is composed of values that are not not known until the genesis block/state are available.
Due to this, clients SHOULD NOT form ENRs and begin peer discovery until genesis values are known.
One notable exception to this rule is the distribution of bootnode ENRs prior to genesis.
In this case, bootnode ENRs SHOULD be initially distributed with eth2
field set as
ENRForkID(fork_digest=compute_fork_digest(GENESIS_FORK_VERSION, b'\x00'*32), next_fork_version=GENESIS_FORK_VERSION, next_fork_epoch=FAR_FUTURE_EPOCH)
.
After genesis values are known, the bootnodes SHOULD update ENRs to participate in normal discovery operations.
Clients SHOULD connect to peers with fork_digest
, next_fork_version
, and next_fork_epoch
that match local values.
Clients MAY connect to peers with the same fork_digest
but a different next_fork_version
/next_fork_epoch
.
Unless ENRForkID
is manually updated to matching prior to the earlier next_fork_epoch
of the two clients,
these connecting clients will be unable to successfully interact starting at the earlier next_fork_epoch
.
libp2p peers can listen on multiple transports concurrently, and these can change over time. Multiaddrs encode not only the address but also the transport to be used to dial.
Due to this dynamic nature, agreeing on specific transports like TCP, QUIC, or WebSockets on paper becomes irrelevant.
However, it is useful to define a minimum baseline for interoperability purposes.
Clients may support other transports such as libp2p QUIC, WebSockets, and WebRTC transports, if available in the language of choice. While interoperability shall not be harmed by lack of such support, the advantages are desirable:
The libp2p QUIC transport inherently relies on TLS 1.3 per requirement in section 7 of the QUIC protocol specification and the accompanying QUIC-TLS document.
The usage of one handshake procedure or the other shall be transparent to the Eth2 application layer, once the libp2p Host/Node object has been configured appropriately.
TCP is a reliable, ordered, full-duplex, congestion-controlled network protocol that powers much of the Internet as we know it today. HTTP/1.1 and HTTP/2 run atop TCP.
QUIC is a new protocol that’s in the final stages of specification by the IETF QUIC WG. It emerged from Google’s SPDY experiment. The QUIC transport is undoubtedly promising. It’s UDP-based yet reliable, ordered, multiplexed, natively secure (TLS 1.3), reduces latency vs. TCP, and offers stream-level and connection-level congestion control (thus removing head-of-line blocking), 0-RTT connection establishment, and endpoint migration, amongst other features. UDP also has better NAT traversal properties than TCP—something we desperately pursue in peer-to-peer networks.
QUIC is being adopted as the underlying protocol for HTTP/3. This has the potential to award us censorship resistance via deep packet inspection for free. Provided that we use the same port numbers and encryption mechanisms as HTTP/3, our traffic may be indistinguishable from standard web traffic, and we may only become subject to standard IP-based firewall filtering—something we can counteract via other mechanisms.
WebSockets and/or WebRTC transports are necessary for interaction with browsers, and will become increasingly important as we incorporate browser-based light clients to the Eth2 network.
Networks evolve. Hardcoding design decisions leads to ossification, preventing the evolution of networks alongside the state of the art. Introducing changes on an ossified protocol is very costly, and sometimes, downright impracticable without causing undesirable breakage.
Modeling for upgradeability and dynamic transport selection from the get-go lays the foundation for a future-proof stack.
Clients can adopt new transports without breaking old ones, and the multi-transport ability enables constrained and sandboxed environments (e.g. browsers, embedded devices) to interact with the network as first-class citizens via suitable/native transports (e.g. WSS), without the need for proxying or trust delegation to servers.
The QUIC standard is still not finalized (at working draft 22 at the time of writing), and not all mainstream runtimes/languages have mature, standard, and/or fully-interoperable QUIC support. One remarkable example is node.js, where the QUIC implementation is in early development.
Note: TLS 1.3 is a prerequisite of the QUIC transport, although an experiment exists to integrate Noise as the QUIC crypto layer: nQUIC.
On the other hand, TLS 1.3 is the newest, simplified iteration of TLS. Old, insecure, obsolete ciphers and algorithms have been removed, adopting Ed25519 as the sole ECDH key agreement function. Handshakes are faster, 1-RTT data is supported, and session resumption is a reality, amongst other features.
Yamux is a multiplexer invented by Hashicorp that supports stream-level congestion control. Implementations exist in a limited set of languages, and it’s not a trivial piece to develop.
Conscious of that, the libp2p community conceptualized mplex as a simple, minimal multiplexer for usage with libp2p. It does not support stream-level congestion control and is subject to head-of-line blocking.
Overlay multiplexers are not necessary with QUIC since the protocol provides native multiplexing, but they need to be layered atop TCP, WebSockets, and other transports that lack such support.
multiselect 2.0 is currently being conceptualized. The debate started on this issue, but it got overloaded—as it tends to happen with large conceptual OSS discussions that touch the heart and core of a system.
At some point in 2020, we expect a renewed initiative to first define the requirements, constraints, assumptions, and features, in order to lock in basic consensus upfront and subsequently build on that consensus by submitting a specification for implementation.
We plan to eventually migrate to multiselect 2.0 because it will:
All libp2p connections must be authenticated, encrypted, and multiplexed. Connections using network transports unsupportive of native authentication/encryption and multiplexing (e.g. TCP) need to undergo protocol negotiation to agree on a mutually supported:
In this specification, we refer to these two as connection-level negotiations. Transports supporting those features natively (such as QUIC) omit those negotiations.
After successfully selecting a multiplexer, all subsequent I/O happens over streams. When opening streams, peers pin a protocol to that stream, by conducting stream-level protocol negotiation.
At present, multistream-select 1.0 is used for both types of negotiation, but multiselect 2.0 will use dedicated mechanisms for connection bootstrapping process and stream protocol negotiation.
SecIO has been the default encryption layer for libp2p for years. It is used in IPFS and Filecoin. And although it will be superseded shortly, it is proven to work at scale.
Although SecIO has wide language support, we won’t be using it for mainnet because, amongst other things, it requires several round trips to be sound, and doesn’t support early data (0-RTT data), a mechanism that multiselect 2.0 will leverage to reduce round trips during connection bootstrapping.
SecIO is not considered secure for the purposes of this spec.
Copied from the Noise Protocol Framework website:
Noise is a framework for building crypto protocols. Noise protocols support mutual and optional authentication, identity hiding, forward secrecy, zero round-trip encryption, and other advanced features.
Noise in itself does not specify a single handshake procedure, but provides a framework to build secure handshakes based on Diffie-Hellman key agreement with a variety of tradeoffs and guarantees.
Noise handshakes are lightweight and simple to understand, and are used in major cryptographic-centric projects like WireGuard, I2P, and Lightning. Various studies have assessed the stated security goals of several Noise handshakes with positive results.
Transport level encryption secures message exchange and provides properties that are useful for privacy, safety, and censorship resistance. These properties are derived from the following security guarantees that apply to the entire communication between two peers:
Note that transport-level encryption is not exclusive of application-level encryption or cryptography. Transport-level encryption secures the communication itself, while application-level cryptography is necessary for the application’s use cases (e.g. signatures, randomness, etc.).
Pubsub is a technique to broadcast/disseminate data across a network rapidly. Such data is packaged in fire-and-forget messages that do not require a response from every recipient. Peers subscribed to a topic participate in the propagation of messages in that topic.
The alternative is to maintain a fully connected mesh (all peers connected to each other 1:1), which scales poorly (O(n^2)).
For future extensibility with almost zero overhead now (besides the extra bytes in the topic name).
Changing gossipsub/broadcasts requires a coordinated upgrade where all clients start publishing to the new topic together, during a hard fork.
When a node is preparing for upcoming tasks (e.g. validator duty lookahead) on a gossipsub topic, the node should join the topic of the future epoch in which the task is to occur in addition to listening to the topics for the current epoch.
Supporting multiple topics/encodings would require the presence of relayers to translate between encodings and topics so as to avoid network fragmentation where participants have diverging views on the gossiped state, making the protocol more complicated and fragile.
Gossip protocols typically remember what messages they’ve seen for a finite period of time-based on message identity – if you publish the same message again after that time has passed, it will be re-broadcast—adding a relay delay also makes this scenario more likely.
One can imagine that in a complicated upgrade scenario, we might have peers publishing the same message on two topics/encodings, but the price here is pretty high in terms of overhead – both computational and networking – so we’d rather avoid that.
It is permitted for clients to publish data on alternative topics as long as they also publish on the network-wide mandatory topic.
Topic names have a hierarchical structure. In the future, gossipsub may support wildcard subscriptions (e.g. subscribe to all children topics under a root prefix) by way of prefix matching. Enforcing hashes for topic names would preclude us from leveraging such features going forward.
No security or privacy guarantees are lost as a result of choosing plaintext topic names, since the domain is finite anyway, and calculating a digest’s preimage would be trivial.
Furthermore, the Eth2 topic names are shorter than their digest equivalents (assuming SHA-256 hash), so hashing topics would bloat messages unnecessarily.
StrictNoSign
signature policy?The policy omits the from
(1), seqno
(3), signature
(5) and key
(6) fields. These fields would:
from
), type of sender (based on seqno
)data
, not on the from
and seqno
.signature
.message-id
?For our current purposes, there is no need to address messages based on source peer, or track a message seqno
.
By overriding the default message-id
to use content-addressing we can filter unnecessary duplicates before hitting the application layer.
Some examples of where messages could be duplicated:
D
, D_low
, D_high
, D_lazy
: recommended defaults.heartbeat_interval
: 0.7 seconds, recommended for eth2 in the GossipSub evaluation report by Protocol Labs.fanout_ttl
: 60 seconds, recommended default.
Fanout is primarily used by committees publishing attestations to subnets.
This happens once per epoch per validator and the subnet changes each epoch
so there is little to gain in having a fanout_ttl
be increased from the recommended default.mcache_len
: 6, increase by one to ensure that mcache is around for long
enough for IWANT
s to respond to IHAVE
s in the context of the shorter
heartbeat_interval
. If mcache_gossip
is increased, this param should be
increased to be at least 3
(~2 seconds) more than mcache_gossip
.mcache_gossip
: 3, recommended default. This can be increased to 5 or 6
(~4 seconds) if gossip times are longer than expected and the current window
does not provide enough responsiveness during adverse conditions.seen_ttl
: SLOTS_PER_EPOCH * SECONDS_PER_SLOT / heartbeat_interval = approx. 550
.
Attestation gossip validity is bounded by an epoch, so this is the safe max bound.MAXIMUM_GOSSIP_CLOCK_DISPARITY
when validating slot ranges of messages in gossip subnets?For some gossip channels (e.g. those for Attestations and BeaconBlocks), there are designated ranges of slots during which particular messages can be sent, limiting messages gossiped to those that can be reasonably used in the consensus at the current time/slot. This is to reduce optionality in DoS attacks.
MAXIMUM_GOSSIP_CLOCK_DISPARITY
provides some leeway in validating slot ranges to prevent the gossip network
from becoming overly brittle with respect to clock disparity.
For minimum and maximum allowable slot broadcast times,
MAXIMUM_GOSSIP_CLOCK_DISPARITY
MUST be subtracted and added respectively, marginally extending the valid range.
Although messages can at times be eagerly gossiped to the network,
the node’s fork choice prevents integration of these messages into the actual consensus until the actual local start of the designated slot.
ATTESTATION_SUBNET_COUNT
attestation subnets?Depending on the number of validators, it may be more efficient to group shard subnets and might provide better stability for the gossipsub channel.
The exact grouping will be dependent on more involved network tests.
This constant allows for more flexibility in setting up the network topology for attestation aggregation (as aggregation should happen on each subnet).
The value is currently set to to be equal MAX_COMMITTEES_PER_SLOT
if/until network tests indicate otherwise.
SLOTS_PER_EPOCH
slots?Attestations can only be included on chain within an epoch’s worth of slots so this is the natural cutoff. There is no utility to the chain to broadcast attestations older than one epoch, and because validators have a chance to make a new attestation each epoch, there is minimal utility to the fork choice to relay old attestations as a new latest message can soon be created by each validator.
In addition to this, relaying attestations requires validating the attestation in the context of the state
during which it was created.
Thus, validating arbitrarily old attestations would put additional requirements on which states need to be readily available to the node.
This would result in a higher resource burden and could serve as a DoS vector.
AggregateAndProof
s rather than just as Attestation
s?The dominant strategy for an individual validator is to always broadcast an aggregate containing their own attestation to the global channel to ensure that proposers see their attestation for inclusion. Using a private selection criteria and providing this proof of selection alongside the gossiped aggregate ensures that this dominant strategy will not flood the global channel.
Also, an attacker can create any number of honest-looking aggregates and broadcast them to the global pubsub channel. Thus without some sort of proof of selection as an aggregator, the global channel can trivially be spammed.
Entire objects should be sent to get the greatest propagation speeds. If only hashes are sent, then block and attestation propagation is dependent on recursive requests from each peer. In a hash-only scenario, peers could receive hashes without knowing who to download the actual contents from. Sending entire objects ensures that they get propagated through the entire network.
The prohibition of unverified-block-gossiping extends to nodes that cannot verify a signature due to not being fully synced to ensure that such (amplified) DOS attacks are not possible.
In Phase 0, peers for attestation subnets will be found using the attnets
entry in the ENR.
Although this method will be sufficient for early phases of Eth2, we aim to use the more appropriate discv5 topics for this and other similar tasks in the future. ENRs should ultimately not be used for this purpose. They are best suited to store identity, location, and capability information, rather than more volatile advertisements.
Fork versions are to be manually updated (likely via incrementing) at each hard fork. This is to provide native domain separation for signatures as well as to aid in usefulness for identitying peers (via ENRs) and versioning network protocols (e.g. using fork version to naturally version gossipsub topics).
BeaconState.genesis_validators_root
is mixed into signature and ENR fork domains (ForkDigest
) to aid in the ease of domain separation between chains.
This allows fork versions to safely be reused across chains except for the case of contentious forks using the same genesis.
In these cases, extra care should be taken to isolate fork versions (e.g. flip a high order bit in all future versions of one of the chains).
A node locally stores all previous and future planned fork versions along with the each fork epoch. This allows for handling sync and processing messages starting from past forks/epochs.
Requests are segregated by protocol ID to:
Caveat: The protocol negotiation component in the current version of libp2p is called multistream-select 1.0. It is somewhat naïve and introduces overhead on every request when negotiating streams, although implementation-specific optimizations are possible to save this cost. Multiselect 2.0 will eventually remove this overhead by memoizing previously selected protocols, and modeling shared protocol tables. Fortunately, this req/resp protocol is not the expected network bottleneck in the protocol so the additional overhead is not expected to significantly hinder this domain.
We are using single-use streams where each stream is closed at the end of the message. Thus, libp2p transparently handles message delimiting in the underlying stream. libp2p streams are full-duplex, and each party is responsible for closing their write side (like in TCP). We can therefore use stream closure to mark the end of the request and response independently.
Nevertheless, in the case of ssz_snappy
, messages are still length-prefixed with the length of the underlying data:
Status
message does not nearly require MAX_CHUNK_SIZE
bytes.Protobuf varint is an efficient technique to encode variable-length (unsigned here) ints. Instead of reserving a fixed-size field of as many bytes as necessary to convey the maximum possible value, this field is elastic in exchange for 1-bit overhead per byte.
Using semver for network protocols is confusing. It is never clear what a change in a field, even if backwards compatible on deserialization, actually implies. Network protocol agreement should be explicit. Imagine two peers:
These two peers should never speak to each other because the results can be unpredictable. This is an oversimplification: imagine the same problem with a set of 10 possible versions. We now have 10^2 (100) possible outcomes that peers need to model for. The resulting complexity is unwieldy.
For this reason, we rely on negotiation of explicit, verbatim protocols. In the above case, peer B would provide backwards compatibility by supporting and advertising both v1.1.1 and v1.1.2 of the protocol.
Therefore, semver would be relegated to convey expectations at the human level, and it wouldn’t do a good job there either, because it’s unclear if “backwards compatibility” and “breaking change” apply only to wire schema level, to behavior, etc.
For this reason, we remove and replace semver with ordinals that require explicit agreement and do not mandate a specific policy for changes.
Req/Resp is used to avoid confusion with JSON-RPC and similar user-client interaction mechanisms.
When requesting blocks by range or root, it may happen that there are no blocks in the selected range or the responding node does not have the requested blocks.
Thus, it may happen that we need to transmit an empty list - there are several ways to encode this:
0) Close the stream without sending any data
1) Add a null
option to the success
response, for example by introducing an additional byte
2) Respond with an error result, using a specific error code for “No data”
Semantically, it is not an error that a block is missing during a slot making option 2 unnatural.
Option 1 allows allows the responder to signal “no block”, but this information may be wrong - for example in the case of a malicious node.
Under option 0, there is no way for a client to distinguish between a slot without a block and an incomplete response, but given that it already must contain logic to handle the uncertainty of a malicious peer, option 0 was chosen. Clients should mark any slots missing blocks as unknown until they can be verified as not containing a block by successive blocks.
Assuming option 0 with no special null
encoding, consider a request for slots 2, 3, 4
– if there was no block produced at slot 4, the response would be 2, 3, EOF
.
Now consider the same situation, but where only 4
is requested
– closing the stream with only EOF
(without any response_chunk
) is consistent.
Failing to provide blocks that nodes “should” have is reason to trust a peer less – for example, if a particular peer gossips a block, it should have access to its parent. If a request for the parent fails, it’s indicative of poor peer quality since peers should validate blocks before gossiping them.
BeaconBlocksByRange
let the server choose which branch to send blocks from?When connecting, the Status
message gives an idea about the sync status of a particular peer, but this changes over time.
By the time a subsequent BeaconBlockByRange
request is processed, the information may be stale,
and the responding side might have moved on to a new finalization point and pruned blocks around the previous head and finalized blocks.
To avoid this race condition, we allow the responding side to choose which branch to send to the requesting client. The requesting client then goes on to validate the blocks and incorporate them in their own database – because they follow the same rules, they should at this point arrive at the same canonical chain.
When syncing one can only tell that a slot has been skipped on a particular branch by examining subsequent blocks and analyzing the graph formed by the parent root. Because the server side may choose to omit blocks in the response for any reason, clients must validate the graph and be prepared to fill in gaps.
For example, if a peer responds with blocks [2, 3] when asked for [2, 3, 4], clients may not assume that block 4 doesn’t exist – it merely means that the responding peer did not send it (they may not have it yet or may maliciously be trying to hide it) and successive blocks will be needed to determine if there exists a block at slot 4 in this particular branch.
discv5 is a standalone protocol, running on UDP on a dedicated port, meant for peer and service discovery only. discv5 supports self-certified, flexible peer records (ENRs) and topic-based advertisement, both of which are, or will be, requirements in this context.
On the other hand, libp2p Kademlia DHT is a fully-fledged DHT protocol/implementations with content routing and storage capabilities, both of which are irrelevant in this context.
Eth 1.0 nodes will evolve to support discv5. By sharing the discovery network between Eth 1.0 and 2.0, we benefit from the additive effect on network size that enhances resilience and resistance against certain attacks, to which smaller networks are more vulnerable. It should also help light clients of both networks find nodes with specific capabilities.
discv5 is in the process of being audited.
Ethereum Node Records are self-certified node records. Nodes craft and disseminate ENRs for themselves, proving authorship via a cryptographic signature. ENRs are sequentially indexed, enabling conflicts to be resolved.
ENRs are key-value records with string-indexed ASCII keys. They can store arbitrary information, but EIP-778 specifies a pre-defined dictionary, including IPv4 and IPv6 addresses, secp256k1 public keys, etc.
Comparing ENRs and multiaddrs is like comparing apples and oranges. ENRs are self-certified containers of identity, addresses, and metadata about a node. Multiaddrs are address strings with the peculiarity that they’re self-describing, composable and future-proof. An ENR can contain multiaddrs, and multiaddrs can be derived securely from the fields of an authenticated ENR.
discv5 uses ENRs and we will presumably need to:
multiaddr
to the dictionary, so that nodes can advertise their multiaddr under a reserved namespace in ENRs. – and/or –Although client software might very well be running locally prior to the solidification of the eth2 genesis state and block,
clients cannot form valid ENRs prior to this point.
ENRs contain fork_digest
which utilizes the genesis_validators_root
for a cleaner separation between chains
so prior to knowing genesis, we cannot use fork_digest
to cleanly find peers on our intended chain.
Once genesis data is known, we can then form ENRs and safely find peers.
When using an eth1 deposit contract for deposits, fork_digest
will be known GENESIS_DELAY
(7 days in mainnet configuration) before genesis_time
,
providing ample time to find peers and form initial connections and gossip subnets prior to genesis.
SSZ is used at the consensus layer, and all implementations should have support for SSZ-encoding/decoding, requiring no further dependencies to be added to client implementations. This is a natural choice for serializing objects to be sent across the wire. The actual data in most protocols will be further compressed for efficiency.
SSZ has well-defined schemas for consensus objects (typically sent across the wire) reducing any serialization schema data that needs to be sent. It also has defined all required types that are required for this network specification.
We compress on the wire to achieve smaller payloads per-message, which, in aggregate, result in higher efficiency, better utilization of available bandwidth, and overall reduction in network-wide traffic overhead.
At this time, libp2p does not have an out-of-the-box compression feature that can be dynamically negotiated and layered atop connections and streams, but it is being considered.
This is a non-trivial feature because the behavior of network IO loops, kernel buffers, chunking, and packet fragmentation, amongst others, need to be taken into account. libp2p streams are unbounded streams, whereas compression algorithms work best on bounded byte streams of which we have some prior knowledge.
Compression tends not to be a one-size-fits-all problem. A lot of variables need careful evaluation, and generic approaches/choices lead to poor size shavings, which may even be counterproductive when factoring in the CPU and memory tradeoff.
For all these reasons, generically negotiating compression algorithms may be treated as a research problem at the libp2p community, one we’re happy to tackle in the medium-term.
At this stage, the wisest choice is to consider libp2p a messenger of bytes, and to make application layer participate in compressing those bytes. This looks different depending on the interaction layer:
Snappy is used in Ethereum 1.0. It is well maintained by Google, has good benchmarks, and can calculate the size of the uncompressed object without inflating it in memory. This prevents DOS vectors where large uncompressed data is sent.
Yes, you can add loggers in your libp2p protocol handlers to log incoming and outgoing messages. It is recommended to use programming design patterns to encapsulate the logging logic cleanly.
If your libp2p library relies on frameworks/runtimes such as Netty (jvm) or Node.js (javascript), you can use logging facilities in those frameworks/runtimes to enable message tracing.
For specific ad-hoc testing scenarios, you can use the plaintext/2.0.0 secure channel (which is essentially no-op encryption or message authentication), in combination with tcpdump or Wireshark to inspect the wire.
The SSZ encoding outputs of each type have size bounds: each dynamic type, such as a list, has a “limit”, which can be used to compute the maximum valid output size. Note that for some more complex dynamic-length objects, element offsets (4 bytes each) may need to be included. Other types are static, they have a fixed size: no dynamic-length content is involved, and the minimum and maximum bounds are the same.
For reference, the type bounds can be computed ahead of time, as per this example. It is advisable to derive these lengths from the SSZ type definitions in use, to ensure that version changes do not cause out-of-sync type bounds.
This section will soon contain a matrix showing the maturity/state of the libp2p features required by this spec across the languages in which Eth2 clients are being developed.
SSZ SimpleSerialize


In {{ mood }} mood, here are some suggestions, you can try:
{{ restaurant["Cuisines"] }}
Avg. Cost for 2 : {{ restaurant["Average Cost for two"] }}
⭐ {{ restaurant["Aggregate rating"] }} Rating
{{ restaurant["Address"] }}
{{ restaurant["Cuisines"] }}
Avg. Cost for 2 : {{ restaurant["Average Cost for two"] }}
⭐ {{ restaurant["Aggregate rating"] }} Rating
{{ restaurant["Address"] }}
{{ restaurant["Cuisines"] }}
Avg. Cost for 2 : {{ restaurant["Average Cost for two"] }}
⭐ {{ restaurant["Aggregate rating"] }} Rating
{{ restaurant["Address"] }}


1 write to IsEnumerated
System.Management.Automation (1)
engine\hostifaces\PSDataCollection.cs (1)
1861
_collToEnumerate.
IsEnumerated
= true;
1 reference to IsEnumerated
System.Management.Automation (1)
engine\hostifaces\PSDataCollection.cs (1)
1855
Dbg.Assert(!collection.ReleaseOnEnumeration || !collection.
IsEnumerated
,


Thanks for using lockdown, your antivirus really appreciates it.
This is a friendly reminder that this template is intended as a joke and not to be used in production !
It seems that you want to get out of this page...
Please remember to :
wash your hands
wear a mask
keep your distances
avoid crowded and poorly ventilated indoors
keep yourself informed with sources based on good science


|
F´ Flight Software - C/C++ Documentation
NASA-v1.5.0
A framework for building embedded system applications to NASA flight quality standards.
|
Functions | |
| Status | validate (const char *fileName, const char *hashFileName, Utils::HashBuffer &hashBuffer) |
| Validate the contents of a file 'fileName' against its hash. More... | |
| Status | validate (const char *fileName, const char *hashFileName) |
| stored in 'hashFileName' More... | |
| Status | createValidation (const char *fileName, const char *hash, Utils::HashBuffer &hashBuffer) |
| Status | createValidation (const char *fileName, const char *hashFileName) |
| in a file 'hashFileName' More... | |
| Enumerator | |
|---|---|
| VALIDATION_OK | The validation of the file passed. |
| VALIDATION_FAIL | The validation of the file did not pass. |
| FILE_DOESNT_EXIST | File doesn't exist (for read) |
| FILE_NO_PERMISSION | No permission to read/write file. |
| FILE_BAD_SIZE | Invalid size parameter. |
| VALIDATION_FILE_DOESNT_EXIST | Validation file doesn't exist (for read) |
| VALIDATION_FILE_NO_PERMISSION | No permission to read/write file. |
| VALIDATION_FILE_BAD_SIZE | Invalid size parameter. |
| NO_SPACE | No space left on the device for writing. |
| OTHER_ERROR | A catch-all for other errors. Have to look in implementation-specific code. |
Definition at line 27 of file ValidateFile.hpp.
| ValidateFile::Status Os::ValidateFile::createValidation | ( | const char * | fileName, |
| const char * | hash, | ||
| Utils::HashBuffer & | hashBuffer | ||
| ) |
Definition at line 205 of file ValidateFileCommon.cpp.
| ValidateFile::Status Os::ValidateFile::createValidation | ( | const char * | fileName, |
| const char * | hashFileName | ||
| ) |
in a file 'hashFileName'
Create a validation of the file 'fileName' and store it in
Definition at line 223 of file ValidateFileCommon.cpp.
| ValidateFile::Status Os::ValidateFile::validate | ( | const char * | fileName, |
| const char * | hashFileName | ||
| ) |
stored in 'hashFileName'
Validate the contents of a file 'fileName' against its hash
Definition at line 172 of file ValidateFileCommon.cpp.
| ValidateFile::Status Os::ValidateFile::validate | ( | const char * | fileName, |
| const char * | hashFileName, | ||
| Utils::HashBuffer & | hashBuffer | ||
| ) |
Validate the contents of a file 'fileName' against its hash.
Definition at line 177 of file ValidateFileCommon.cpp.


Welcome, this webpage was created to showcase history of the internet for IS 117.
You can start by clicking anyone of the tabs on the nav bar to learn more about the appropriate titles.


Akan names are derived from Ghanian culture. Frequently in Ghana, children are given their first name as a 'day name' which corresponds to the day in the week they were born and the child's gender.
Fill in your details below to find out yours


Bridge is a bidirectional communication system between JavaScript and the Ruby environment.
SketchUp Bridge aims to encourage good programming practices:
Bridge is based on promises. Promises help us to write clean asynchronous code as easily as synchronous code and keep subsequent operations together. Promises are proxies for values that are initially unknown. You provide a callback that is called once that the value is known, and optionally a callback for when retrieving the value failed. A promise supports two methods:
All of these methods themselves return a promise, so you can chain methods as if the code in the callbacks was sequential:
promise.then(callback1).then(callback2).then(callback3)
or even:
let result0 = await promise
let result1 = await callback1(result0)
let result2 = await callback2(result1)
let result3 = await callback3(result2)
Without promises all these callbacks would be spread in different places and the sequential structure would not be obvious, which makes the code hard to understand and hard to maintain.
(For a deeper introduction to the advantages of promises, see this blog post.
First you instatiate the Bridge class with a dialog to which the bridge should be connected. Then you can attach callbacks to the Bridge instance using the shorter on method, analog to add_action_callback. In contrast to add_action_callback, the registered code block receives as first parameter a proxy to the dialog (analog) that has been extended (new) to serve as a "deferred" object that is able to resolve or reject the promise of the requested result.
dialog = UI::HtmlDialog.new()
bridge = Bridge.new(dialog)
bridge.on('callback_name') { |deferred|
# Callback code
}
For convenience, you can also extend the dialog instance with the Bridge methods.
dialog = UI::HtmlDialog.new()
Bridge.decorate(dialog)
dialog.on('callback_name') { |deferred|
# Callback code
}
Send a request from the dialog to Ruby and receive the response.
Showing and loading the dialog is asynchronous. That means when the Ruby method dialog.show
finishes, the dialog is not fully loaded, so you cannot immediately call dialog.execute_script
. Instead of making your Ruby code push data to the dialog (not knowing whether the dialog is able to respond), make your dialog fetch data whenever it needs. That means the Ruby part acts like a server, and the dialog is the client.
While the browser reads the HTML file, your initialization JavaScript can only access elements above the <script> element (because only these have been loaded). If you choose to add your script in the <head> section or an external file, use the following pattern to initialize your dialog:
dialog.on('settings') { |deferred|
deferred.resolve(@settings)
}
function initialize () {
Bridge.get('settings').then(function (settings) {
// Do something with the settings, initialize your app etc.
}
}
// Register a handler for the event when the document has been loaded.
// If you use jQuery, you can use $(function () { }) instead.
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initialize);
} else {
initialize();
}
When an error happens, you may want to know about it. You can handle errors in Ruby or in JavaScript.
dialog.on('compute_result1') { |deferred, arg1, arg2|
# SketchUp's native dialog callbacks do not raise errors.
# When an error is raised, Bridge rejects the deferred promise automatically.
# Then your dialog's JavaScript code can handle the error.
result = compute_result1(arg1, arg2)
deferred.resolve(result)
}
Bridge.get('compute_result1', argument1, argument2).then(function (result) {
// Do something with the result
}, function (error) {
// Do any kind of error handling, choose an alternative code path,
// or display a friendly message to the user.
});
dialog.on('compute_result2') { |deferred, arg1|
# If you want to handle the error in Ruby, you should include `begin/rescue`
# in the callback. You can also forward custom data to the error handling JavaScript.
begin
result = compute_result2(arg1)
deferred.resolve(result)
rescue Math::DomainError => error
$stderr.write(error.message)
$stderr.write(error.backtrace.join($\))
# Do any kind of error handling:
# provide an alternative result (e.g. 0) that allows continuing the computation,
# or return a friendly human-readable error message,
# or provide a link/form to report the error to the developer.
deferred.reject('Oh! Too bad, the square root of zero exists only in imagination. Please choose a different number.')
end
}
Bridge.get('compute_result2', number).then(function (result) {
// Do something with the result
}, function (error) {
// Do any kind of error handling, choose an alternative code path,
// or display a friendly message to the user.
});
A promise does not need to return the result immediately. This allows you to continue your JavaScript code later, no matter how long it takes. For example your Ruby code may have called an external program, or downloaded a big file from the internet, or called a custom Select tool that resolves the promise only once that the user has picked an entity.
Bridge.get('compute_asynchronously').then(function (result) {
// That may take long, but the callback is only called when the computation finished.
});
Sometimes you want to trigger some action, but don't receive a result. The method Bridge.call works the same way, but does not return a promise.
Bridge.call('select_pushpull');
If you are tired of writing function and don't need to support WebDialogs, you can use modern JavaScript features like:
Bridge.get('settings').then(settings => alert(settings))
async function myAsyncFunction () {
// As you know, Bridge.get returns a promise, not the result.
let result1 = await Bridge.get('compute_result1', 4, 2)
// The await keyword "converts" all subsequent code into a thenable that is
// only run when the promise is resolved. This is non-blocking!
// Do something with result1. This can again be asynchronous!
let result2 = await Bridge.get('compute_result2', result1)
// Do something with result2. You can insert it into the output field,
// or return it. The async keywords "converts" the return value into a promise.
return result2
}
In some cases, you want to push updates from Ruby to the dialog (when the dialog is loaded), for example when an observer was triggered because an entity was changed or the user selected a different entity. The same functions call and get work also on the bridge/dialog instance in Ruby. Using the Bridge.call method instead of execute_script ensures all arguments are properly encoded.
entity_name = 'ComponentInstance#1'
attributes = {'lenx': 71.0, 'leny': 32.5, 'lenz': 39.5}
dialog.call('entitySelected', entity_name, attributes)
function entitySelected (entityName, attributes) {
// Do something with the parameters, like updating the user interface.
// Alternatively to using parameters, you could fetch data from Ruby with Bridge.get.
}
changed_entity = 'ComponentInstance#1'
attributes = {'lenx': 71.0, 'leny': 32.5, 'lenz': 39.5}
dialog.get('syncToServer', changed_entity, attributes).then{ |server_response|
puts(server_response['body'])
# Do something with the result or continue in the plugin.
}.catch{
puts(server_response['statusText'])
# Handle the error.
}
function syncToServer (entityName, attributes) {
// Do something with the parameters, like sending a request to a remote server.
// Return the result or a promise that will resolve later to the result.
// Example using jQuery:
return new Promise(function(resolve, reject) {
$.ajax({
url: 'www.example.com/app/synchronize-model',
method: 'POST',
data: {action: 'update', 'entity': entityName, 'attributes': attributes}
}).done(resolve).fail(reject);
});
}


Founder and CTO @ Joyn, a communication platform supercharged by AI. With a Master's degree in Computer Science from BU and a background in Chemistry and Computer Science, he bridges scientific principles with technological innovation. Previously, Rishab co-founded Mount, a pioneering rental platform. His research and engineering expertise, particularly in cloud computing, enables him to architect scalable and secure systems. At Joyn, Rishab leads the development of cutting-edge AI technologies that redefine communication. By integrating machine learning and natural language processing, Joyn enables effortless and intelligent connections. If this sounds interesting to you, come join us - we’re hiring!
Sample Preparation, Calorimetry, Titration, Inorganic Synthesis, Freezing Point Depression, Molecular Dynamics (Chimera, AutoDock, VMD)
Spectroscopy (UV-Vis, IR, FAAS, MP-AES), Flow Cytometry, PCR, Gel Electrophoresis
Java, Dart, Javascript, Python, Swift, Objective-C, Node.JS, Wolfram Language, MATLAB
Flutter, Vue.JS, Angular, Mongo, Git, AWS, Google Cloud, Firebase, OpenCV, Keras, CI/CD
Reading, Writing and Speaking Proficiency in English and Hindi, Speaking Proficiency in Oriya
Scientific Writing Proficiency, Black Belt (1st Dan), Electronic Keyboard (Grade 5, Trinity College of Music)
M.S. Computer Science - GPA - 3.95
B.A. Computer Science, Chemistry - CS GPA - 3.60
Founder and CTO
Founder and CTO
Sr. Project and Solutions Manager
Cloud, DevOps and Full Stack Flutter Engineer
Head of Technology
Co-Founder
Core Technology Developer
A mobile based application to quantify the microalbumin levels in urine, an early marker of forthcoming kidney damage.
Optimized production of Gold Nanoparticle based biosensors that can be used to quantify microRNA.
An evaluation of the kinetics and rate of aquation of trans-dichlorobis(ethylenediamine) cobalt(III) chloride
A personal healthcare assistant using voice recognition technology to enable better access to medical assistance
Provides the user contextual awareness, giving them audio feedback on the objects found in their surroundings.
Aids the visually impaired to find empty tables in restaurants and recognize known faces, thereby providing contextual awareness.
A low-cost fully automated IOT Pill Dispenser with a remotely accessible setup UI, all from a RasPi.
A Performance Analysis of Neural Networks to Identify Plugs and Connectors from an Image, created with Wolfram Language.
Computational Screening of compounds having specific binding to DNA-RNA hybrids, using Chimera, AutoDock and parts of Amber
A Novel Bioengineered Adenovirus to Reverse the Effects of Biological Aging by Replenishing Telomeres
Esterifying Free Fatty Acids and Phospholipids in Algal Oil to Increase the Yield of BioDiesel from Feedstock
Using Artificial Neural Networks and Machine Learning to convert lip movements to text using MATLAB
Using advanced image processing algorithms to identify a plant disease from its image.
(Designed in MATLAB)


Team Leader & Software Architect at Quicken Loans, Microsoft Visual C# MVP, Organizer of Desert Code Camp, Husband of one, Father of two.
This demo site was created based on content found at http://www.getbootstrap.com and http://www.fontawesome.io
The source code for this site can be found on GitHub


{% block nav %} {% include "partials/nav.html" %} {% endblock %}
Nine Letter Word Scramble
?
Entry
Enter your guess for the nine letter word here
Skip
Check
?


First meetings were held in a large rented tent in University City. The church used several locations over the years, eventually moving to property at 4000 Washington Blvd. where the ministry stayed for 26 years.
IFCA Founded
1930
Oscar B. Bottorff, founder of the St. Louis Gospel Center, was instrumental in the organization of the new movement.
The First Move
1952
Moved to property on Lindell Blvd. Eventual name change to Lindell Blvd Bible Church in 1957.
The Second Move
1970—Present
Occupied new facilities at 4111 Von Talge Rd in South St. Louis County and changed the name to South County Bible Church.
The Centennial Celebration Year
April 12, 2018
This year marks the 100th birthday of our church. Come celebrate with us and see what God has in store for us next!
Summit Club
September–May
Youth Ministry
Summit Club, a mid-week Bible club, is an exciting new curriculum, from Discipleland, where students gather in a large group setting to experience God's Word in fun and unique ways. They then gather into small groups by age, where they learn to love God and each other. A fun game or craft time rounds out the evening. Service projects are also scheduled for the school year.
Our 3-fold purpose:
To lead kids to know Jesus Christ
To teach them to live for Him
To prepare them to defend their faith
What: A high energy, fast paced, fun Bible club
Who: Kids 3 years old—6th grade
When: Wednesdays 6:45-8:15 PM | September–May
How: Bible lessons, workbooks, games, special events, service projects
Camp Sunago
Youth and Teen Ministry
Camp Sunago takes place at Pinecrest Campground in beautiful Ozark country near Fredericktown, Missouri. Pinecrest is a heavily wooded retreat center about 80 miles south of St Louis. It provides excellent facilities run by the Church of the Nazarene. They go out of their way to make our time there successful and rewarding. We are the only group on campus for the week.
Camp Sunago has all the sun and fun that you have come to expect from a resident summer camp. The Sunago difference is found in our top quality, nationally recognized bible teachers, challenging missionary guests, and bible memorization program.
Our well rounded program will leave your child challenged from God’s Word, excited about world-wide missions, encouraged in their Christian walk, and ready to face their world unashamed of the Gospel.
Camp Sunago is a ministry of South County Bible Church in cooperation with the Greater St. Louis IFCA Regional.
When: July 23-29, 2018
Where: Pinecrest Campground, Fredericktown, MO
R.I.S.E.
(Righteously Influencing Society for Eternity)
Youth and Teen Ministry
Encouraging and Equipping Youth for Service in the Local Church
Like no other time in history, youth are looking for real answers to life's questions. They want to know truth, not just trends and traditions. Our Youth Group at SCBC, is all about communicating truth...Biblical Truth!
Our Youth Group believes in and promotes absolutes for young people like:
Bible Study
Scripture tells us to be ready always to give an answer for the reason of our hope. Young people need to know the Bible, not just about it. We provide a complete Biblical curriculum including survey, topical study and an in-depth look at doctrine.
Small Groups
Each time we gather, there is time set aside to break into smaller groups and discuss the truths discovered in the Bible Study time as well as an opportunity to share prayer requests and offer encouragement in the students walk with Christ.
Service in the Local Church
Christ did not come to be served, but to serve. In addition to a consistent intake of the Word of God, we strive to provide training opportunities for service in the church and outlets to serve in the community and neighborhood.
Scripture Memory
"These words which I command thee this day shall be in thine heart." One of the greatest spiritual weapons available to youth today is scripture memory. We participate in IFCA Bible Quizzing as an outlet for encouraging systematic memory of large portions of God’s Word.
Activities
We recognize that teens also need an outlet to just have fun and be with like-minded believers. We provide monthly activities and outings designed to encourage the inviting of new individuals (saved or unsaved) and to build lasting friendships.
Friendship Club
Special Needs Adult Ministry
Friendship Club is an exciting new group for adults with special needs. No matter the ability or need, all are welcome. Activities include games, singing, prayer time, refreshments, Bible study, and small groups.
When: Alternating Sundays, 3:30 PM
Where: South County Bible Church, Bottorff Hall
Our Missionaries
Go therefore and make disciples of all the nations, baptizing them in the name of the Father and the Son and the Holy Spirit, teaching them to observe all that I commanded you -Matthew 28:19-20a
South County Bible Church is committed to making disciples of Jesus Christ both locally and around the globe. We are committed to supporting the following families on a financial basis as an extension of South County Bible Church. Would you commit to praying for these families as they serve our Savior?
Brady and Candy serve in Johannesburg, South Africa with Biblical Ministries Worldwide. The primary focus of their ministry is in church planting and education. They also work with an orphanage.
Matt and Tracy serve stateside as maintenance staff at the Doe River Gorge Camp and Retreat Center in Elizabethton, TN. We are proud to be the sending church for this missionary family.
The Loves serve as missionaries in Brandon, England with Biblical Ministries Worldwide. The have a diverse ministry which reaches into their community with the gospel of Christ through small churches, bible studies and photography clubs.
David and Brenda serve with Crossworld in Ecuador. They are stationed in the town of Cayambe and the primary focus of their ministry is church planting.
ecuadormeyers.com
Al and Chris serve in the South Eastern quadrant of Michigan with RBM Ministries. The primary focus of their ministry involves working with school age children through release time Bible classes during the public school day and Vacation Bible Schools.
Lee and Diane serve as church planters in Utah. Lee is currently the senior pastor at Payson Bible Church.
paysonbiblechurch.com
Serving in:
Payson, Utah
Affiliated with:
IFCA Bible Quizzing
Youth and Teen Ministry
Bible Quizzing is an exciting teaching mechanism to help youth memorize Scripture through friendly competition. The National Tournament is run by IFCA. It has Senior and Novice Division Championships.
Our goal is to equip young believers with God's Word for application in their daily lives. Participants practice on Monday nights. Memorization ranges from individual verses to entire chapters.
Weekly Bible Study
Adult Ministry
We offer weekly Bible study opportunities for adults during the Sunday School hour (9:00 AM Sundays) and seasonal opportunities for small group Bible study during the week.
Women's Groups
Adult and Senior Ministry
Our ladies are very active and take their faith very seriously. There are many activities year-round to get involved with. There is a mix of encouragement, study, and fun!


This is a three-component point in space (as opposed to a three-component vector, which represents a direction and a distance).
 More...
|
| |
| LPoint2i | getXz () |
| | Returns a 2-component vector that shares just the first and last components of this vector. More...
|
| |
| LPoint2i | getYz () |
| | Returns a 2-component vector that shares just the last two components of this vector.  More...
|
| |
| int | compareTo (const LVecBase3i other) |
| | This flavor of compare_to uses a default threshold value based on the numeric type. More...
|
| |
| | componentwiseMult (const LVecBase3i other) |
| |
| LVecBase3i | cross (const LVecBase3i other) |
| |
| | crossInto (const LVecBase3i other) |
| |
| int | dot (const LVecBase3i other) |
| |
| | fill (int fill_value) |
| | Sets each element of the vector to the indicated fill_value. More...
|
| |
| LVecBase3i | fmax (const LVecBase3i other) |
| |
| LVecBase3i | fmin (const LVecBase3i other) |
| |
| | generateHash (ChecksumHashGenerator hashgen) |
| | Adds the vector to the indicated hash generator. More...
|
| |
| int | getCell (int i) |
| |
| | getData () |
| | Returns the address of the first of the three data elements in the vector. More...
|
| |
| int | getHash () |
| | Returns a suitable hash for phash_map. More...
|
| |
| int | getX () |
| |
| LVecBase2i | getXy () |
| | Returns a 2-component vector that shares just the first two components of this vector. More...
|
| |
| LVecBase2i | getXz () |
| | Returns a 2-component vector that shares just the first and last components of this vector. More...
|
| |
| int | getY () |
| |
| LVecBase2i | getYz () |
| | Returns a 2-component vector that shares just the last two components of this vector. More...
|
| |
| int | getZ () |
| |
| bool | isNan () |
| | Returns true if any component of the vector is not-a-number, false otherwise. More...
|
| |
| int | lengthSquared () |
| | Returns the square of the vector's length, cheap and easy. More...
|
| |
| | operator new (int size) |
| |
| bool | operator!= (const LVecBase3i other) |
| |
| LVecBase3i | operator* (int scalar) |
| |
| LVecBase3i | operator*= (int scalar) |
| |
| LVecBase3i | operator+ (const LVecBase3i other) |
| |
| LVecBase3i | operator+= (const LVecBase3i other) |
| |
| LVecBase3i | operator- () |
| |
| LVecBase3i | operator- (const LVecBase3i other) |
| |
| LVecBase3i | operator-= (const LVecBase3i other) |
| |
| LVecBase3i | operator/ (int scalar) |
| |
| LVecBase3i | operator/= (int scalar) |
| |
| bool | operator< (const LVecBase3i other) |
| |
| LVecBase3i | operator= (const LVecBase3i copy) |
| |
| LVecBase3i | operator= (int fill_value) |
| |
| bool | operator== (const LVecBase3i other) |
| |
| int | operator[] (int i) |
| |
| | operator[] (int i, int assign_val) |
| |
| | output (Ostream out) |
| |
| | readDatagram (DatagramIterator source) |
| | Reads the vector from the Datagram using get_stdfloat(). More...
|
| |
| | readDatagramFixed (DatagramIterator source) |
| | Reads the vector from the Datagram using get_float32() or get_float64().  More...
|
| |
| | writeDatagramFixed (Datagram destination) |
| | Writes the vector to the Datagram using add_float32() or add_float64(), depending on the type of floats in the vector, regardless of the setting of Datagram::set_stdfloat_double(). More...
|
| |
This is a three-component point in space (as opposed to a three-component vector, which represents a direction and a distance).
Some of the methods are slightly different between LPoint3 and LVector3; in particular, subtraction of two points yields a vector, while addition of a vector and a point yields a point.


Python Tkinter LabelThe Label is used to specify the container box where we can place the text or images. This widget is used to provide the message to the user about other widgets used in the python application. There are the various options which can be specified to configure the text or the part of the text shown in the Label. The syntax to use the Label is given below. SyntaxA list of possible options is given below.
Example 1Output:
Next TopicPython Tkinter Listbox
|
Python Tkinter LabelThe Label is used to specify the container box where we can place the text or images. This widget is used to provide the message to the user about other widgets used in the python application. There are the various options which can be specified to configure the text or the part of the text shown in the Label. The syntax to use the Label is given below. SyntaxA list of possible options is given below.
Example 1Output:
Next TopicPython Tkinter Listbox
|
Python Tkinter LabelThe Label is used to specify the container box where we can place the text or images. This widget is used to provide the message to the user about other widgets used in the python application. There are the various options which can be specified to configure the text or the part of the text shown in the Label. The syntax to use the Label is given below. SyntaxA list of possible options is given below.
Example 1Output:
Next TopicPython Tkinter Listbox
|
Python Tkinter LabelThe Label is used to specify the container box where we can place the text or images. This widget is used to provide the message to the user about other widgets used in the python application. There are the various options which can be specified to configure the text or the part of the text shown in the Label. The syntax to use the Label is given below. SyntaxA list of possible options is given below.
Example 1Output:
Next TopicPython Tkinter Listbox
|


She wore an armband with a broad band around it, signifying that she was now part of a broadband network of like-minded individuals. [G|D]
Knowing the goods she was smuggling were contraband, she quickly disbanded her associates and wrapped a headband around her forehead in hopes of becoming inconspicuous. [G|D]
She nervously adjusted her husband's neckband and noseband as she walked down the aisle, feeling his reassuring presence with every step. [G|D]
She gracefully glided across the dance floor, her saraband steps echoing in time with the music as her waistband and wristband shimmered in the light. [G|D]


Project name
Logged in as
Username
Home
About
Contact
Examples
TODO
TODO 2
Refer Friends
Super Add
Refer a friend
Add friend
Name
Email
Remove
Dear
, we hope...
You need to add
more friends.
Alright! You've added 5 friends!


List of Puzzles
Your team's score:
Hint credit(s) left:
Part 1 (Murder Location)
Part 2 (Murder Weapon)
Final Puzzle (Murderer): [10pts] His Last Bow


Recycle your PRESENT to SAVE your FUTURE
RECYLING IN LAST FEW YEARS
percentage of recycling in different years
Recycled materials percentage in last 5 years
{{#each info}}
{{/info}}
REUSE
REDUCE
RECYCLE


In case your username is not elm, replace elm in the following code with your username.
Open a terminal window, and type:
ssh<EMAIL_ADDRESS>Enter your password when prompted.
In the terminal window where you sshed into athena, type:
cd www
pwd
Copy the filepath you see -- this is where you'll put the contents of the website. For me it was:
/afs/athena.mit.edu/user/e/l/elm/www
Navigate out of ssh by opening another terminal or typing:
exit
Let's say the file you want to add to www is called index.html, and is in your Downloads folder, and your username is elm. Then type:
scp ~/Downloads/index.html elm@athena.dialup.mit.edu:/afs/athena.mit.edu/user/e/l/elm/www/index.html


Seniman
Home
Sculptor
Product
"get your awesome sculptures from local sculptor today."
Most Rated Sculptors
View all
Herika Sutanto
Ki Ageng Gundayana
I Made Putranto
Dolorosa Sinaga
Edhi Sunarso
Hindra PY
Ibnu Nurwanto
Amrus
Gatot Pratama
Gurat
Most Rated Product
View all
Highlighted Stories
History of Selamat Datang Sculpture
143 views
Ari Adiprana
Proklamator Sculpture is Unveiled by the President
514 views
Ari Adiprana
Edhi Sunarso and His Masterpiece
1931 views
Ari Adiprana


Linda Belcher
Linda is Bob's saucy wife.
Favorite Linda quotes:
- Alriiiiiiiiight!

Linda is Bob's saucy wife.


TweetAllEars
Search
Location
Login
See the world in the different way
Let's sign-in to the next step
UserName:
Password:
Submit
Haven't register ?


No. 14 Badgers lead Nebraska at half, 27-14
by Stephen CohnLINCOLN, Neb. - Wisconsin's Big Ten West title hopes are slim after dropping back-to-back road games at Illinois and Ohio State, but things are looking a bit different Saturday in Lincoln.
After a half of big plays, the No. 14 Badgers lead the Cornhuskers, 27-14.
Despite turning the ball over and falling behind 7-0, Wisconsin (7-2) found its groove on Aron Cruickshank's 89-yard kickoff return for a score. That's when the Badgers' offense took with a field goal, A.J. Taylor's 55-yard touchdown reception, an interception and a short-field score for Jonathan Taylor.
But it was the Badgers team we've become familiar with that ended the half-ended the half on a four-minute ground-and-pound scoring drive and a field goal.
Nebraska (4-5) has struggled all season and is looking for its first bowl in a couple of years, but extended head coach Scott Frost on Saturday morning before the game, despite starting his coaching career in Lincoln 8-13.
Wisconsin returns home next Saturday to Camp Randall for Senior Day against Purdue.
If Minnesota loses to Iowa later this afternoon and Wisconsin wins out (vs. Purdue, at Minnesota), the Badgers represent the division in next month's Big Ten Championship Game.


This start up is a one person company incorporated with the aim of carrying out a sustainable business in the field of Sustainability, Green Energy and Real Estate Consultancy.
Sustainability of the Environment, Business, Relationships, Employees. In short this forms the pillars of the success of any enterprise. This is something that we would like to facilitate.
 This extends beyond energy conservation it also deals with the non-degradation of the environment while we live in this world.


Separate multiple addresses with commas. Limited to 10 recipients. We will not share any of the email addresses on this form with third parties.
300-character limit


From: John Compass
To: Samuel Compass
Subject: Martin
Dearest Sam, I just spoke to Martin, vis a vis his recently published novel. Quite frankly, I don’t think he has it in him to ever be a great writer, or even a particularly good one, at least not from a literary viewpoint. However, he seems to be enjoying himself, and I think he might make a decent hack writer someday. I’m just afraid he’ll by crushed by the reception of his novel. The basic story is a decent conspiracy yarn, but the execution is sorely lacking. With a good editor, and a few rewrites, I think it might find an audience. I just know that he won’t take my criticism seriously. He is convinced that my standards are just too high, I compare everything to Tolstoy, etc. Do you think you could talk to him?
From: Samuel Compass
To: John Compass
Subject: Re: Martin
Hi, Dad, I was just thinking the same thing :). I think I like his book better than you do, but I definitely agree that it could use a rewrite. We’re going out to The Goose later, so I’ll talk to him then.