mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-09 21:38:05 -05:00
Update go to 1.19.3 (#11630)
* Update go to 1.19.3 * Update other items to 1.19 * Update golangci-lint to latest release * Run gofmt -s with go1.19 * Huge gofmt changes Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>
This commit is contained in:
@@ -56,29 +56,29 @@ type Chunker interface {
|
||||
// Under ideal network conditions, where every target epoch immediately follows its source,
|
||||
// min spans for a validator will look as follows:
|
||||
//
|
||||
// min_spans = [2, 2, 2, ..., 2]
|
||||
// min_spans = [2, 2, 2, ..., 2]
|
||||
//
|
||||
// Next, we can chunk this list of min spans into chunks of length C. For C = 2, for example:
|
||||
//
|
||||
// chunk0 chunk1 chunkN
|
||||
// { } { } { }
|
||||
// chunked_min_spans = [[2, 2], [2, 2], ..., [2, 2]]
|
||||
// chunk0 chunk1 chunkN
|
||||
// { } { } { }
|
||||
// chunked_min_spans = [[2, 2], [2, 2], ..., [2, 2]]
|
||||
//
|
||||
// Finally, we can store each chunk index for K validators into a single flat slice. For K = 3:
|
||||
//
|
||||
// val0 val1 val2
|
||||
// { } { } { }
|
||||
// chunk_0_for_validators_0_to_2 = [[2, 2], [2, 2], [2, 2]]
|
||||
// val0 val1 val2
|
||||
// { } { } { }
|
||||
// chunk_0_for_validators_0_to_2 = [[2, 2], [2, 2], [2, 2]]
|
||||
//
|
||||
// val0 val1 val2
|
||||
// { } { } { }
|
||||
// chunk_1_for_validators_0_to_2 = [[2, 2], [2, 2], [2, 2]]
|
||||
// val0 val1 val2
|
||||
// { } { } { }
|
||||
// chunk_1_for_validators_0_to_2 = [[2, 2], [2, 2], [2, 2]]
|
||||
//
|
||||
// ...
|
||||
// ...
|
||||
//
|
||||
// val0 val1 val2
|
||||
// { } { } { }
|
||||
// chunk_N_for_validators_0_to_2 = [[2, 2], [2, 2], [2, 2]]
|
||||
// val0 val1 val2
|
||||
// { } { } { }
|
||||
// chunk_N_for_validators_0_to_2 = [[2, 2], [2, 2], [2, 2]]
|
||||
//
|
||||
// MinSpanChunksSlice represents the data structure above for a single chunk index.
|
||||
type MinSpanChunksSlice struct {
|
||||
@@ -175,7 +175,7 @@ func (m *MaxSpanChunksSlice) Chunk() []uint16 {
|
||||
// within the min span chunks slice. Recall that for an incoming attestation, B, and an
|
||||
// existing attestation, A:
|
||||
//
|
||||
// B surrounds A if and only if B.target > min_spans[B.source]
|
||||
// B surrounds A if and only if B.target > min_spans[B.source]
|
||||
//
|
||||
// That is, this condition is sufficient to check if an incoming attestation
|
||||
// is surrounding a previous one. We also check if we indeed have an existing
|
||||
@@ -222,7 +222,7 @@ func (m *MinSpanChunksSlice) CheckSlashable(
|
||||
// within the max span chunks slice. Recall that for an incoming attestation, B, and an
|
||||
// existing attestation, A:
|
||||
//
|
||||
// B surrounds A if and only if B.target < max_spans[B.source]
|
||||
// B surrounds A if and only if B.target < max_spans[B.source]
|
||||
//
|
||||
// That is, this condition is sufficient to check if an incoming attestation
|
||||
// is surrounded by a previous one. We also check if we indeed have an existing
|
||||
@@ -278,19 +278,19 @@ func (m *MaxSpanChunksSlice) CheckSlashable(
|
||||
// Recall that a MinSpanChunksSlice struct represents a single slice for a chunk index
|
||||
// from the collection below:
|
||||
//
|
||||
// val0 val1 val2
|
||||
// { } { } { }
|
||||
// chunk_0_for_validators_0_to_2 = [[2, 2], [2, 2], [2, 2]]
|
||||
// val0 val1 val2
|
||||
// { } { } { }
|
||||
// chunk_0_for_validators_0_to_2 = [[2, 2], [2, 2], [2, 2]]
|
||||
//
|
||||
// val0 val1 val2
|
||||
// { } { } { }
|
||||
// chunk_1_for_validators_0_to_2 = [[2, 2], [2, 2], [2, 2]]
|
||||
// val0 val1 val2
|
||||
// { } { } { }
|
||||
// chunk_1_for_validators_0_to_2 = [[2, 2], [2, 2], [2, 2]]
|
||||
//
|
||||
// ...
|
||||
// ...
|
||||
//
|
||||
// val0 val1 val2
|
||||
// { } { } { }
|
||||
// chunk_N_for_validators_0_to_2 = [[2, 2], [2, 2], [2, 2]]
|
||||
// val0 val1 val2
|
||||
// { } { } { }
|
||||
// chunk_N_for_validators_0_to_2 = [[2, 2], [2, 2], [2, 2]]
|
||||
//
|
||||
// Let's take a look at how this update will look for a real set of min span chunk:
|
||||
// For the purposes of a simple example, let's set H = 2, meaning a min span
|
||||
@@ -301,12 +301,11 @@ func (m *MaxSpanChunksSlice) CheckSlashable(
|
||||
// 4 down to 3. First, we find out which chunk epoch 4 falls into, which is calculated as:
|
||||
// chunk_idx = (epoch % H) / C = (4 % 2) / 2 = 0
|
||||
//
|
||||
//
|
||||
// val0 val1 val2
|
||||
// { } { } { }
|
||||
// chunk_0_for_validators_0_to_3 = [[2, 2], [2, 2], [2, 2]]
|
||||
// |
|
||||
// |-> epoch 4 for validator 0
|
||||
// val0 val1 val2
|
||||
// { } { } { }
|
||||
// chunk_0_for_validators_0_to_3 = [[2, 2], [2, 2], [2, 2]]
|
||||
// |
|
||||
// |-> epoch 4 for validator 0
|
||||
//
|
||||
// Next up, we proceed with the update process for validator index 0, starting at epoch 4
|
||||
// all the way down to epoch 2. We will need to go down the array as far as we can get. If the
|
||||
@@ -452,18 +451,18 @@ func (_ *MaxSpanChunksSlice) StartEpoch(
|
||||
// NextChunkStartEpoch given an epoch, determines the start epoch of the next chunk. For min
|
||||
// span chunks, this will be the last epoch of chunk index = (current chunk - 1). For example:
|
||||
//
|
||||
// chunk0 chunk1 chunk2
|
||||
// | | |
|
||||
// max_spans_val_i = [[-, -, -], [-, -, -], [-, -, -]]
|
||||
// chunk0 chunk1 chunk2
|
||||
// | | |
|
||||
// max_spans_val_i = [[-, -, -], [-, -, -], [-, -, -]]
|
||||
//
|
||||
// If C = chunkSize is 3 epochs per chunk, and we input start epoch of chunk 1 which is 3 then the next start
|
||||
// epoch is the last epoch of chunk 0, which is epoch 2. This is computed as:
|
||||
//
|
||||
// last_epoch(chunkIndex(startEpoch)-1)
|
||||
// last_epoch(chunkIndex(3) - 1)
|
||||
// last_epoch(1 - 1)
|
||||
// last_epoch(0)
|
||||
// 2
|
||||
// last_epoch(chunkIndex(startEpoch)-1)
|
||||
// last_epoch(chunkIndex(3) - 1)
|
||||
// last_epoch(1 - 1)
|
||||
// last_epoch(0)
|
||||
// 2
|
||||
func (m *MinSpanChunksSlice) NextChunkStartEpoch(startEpoch types.Epoch) types.Epoch {
|
||||
prevChunkIdx := m.params.chunkIndex(startEpoch)
|
||||
if prevChunkIdx > 0 {
|
||||
@@ -475,18 +474,18 @@ func (m *MinSpanChunksSlice) NextChunkStartEpoch(startEpoch types.Epoch) types.E
|
||||
// NextChunkStartEpoch given an epoch, determines the start epoch of the next chunk. For max
|
||||
// span chunks, this will be the start epoch of chunk index = (current chunk + 1). For example:
|
||||
//
|
||||
// chunk0 chunk1 chunk2
|
||||
// | | |
|
||||
// max_spans_val_i = [[-, -, -], [-, -, -], [-, -, -]]
|
||||
// chunk0 chunk1 chunk2
|
||||
// | | |
|
||||
// max_spans_val_i = [[-, -, -], [-, -, -], [-, -, -]]
|
||||
//
|
||||
// If C = chunkSize is 3 epochs per chunk, and we input start epoch of chunk 1 which is 3. The next start
|
||||
// epoch is the start epoch of chunk 2, which is epoch 4. This is computed as:
|
||||
//
|
||||
// first_epoch(chunkIndex(startEpoch)+1)
|
||||
// first_epoch(chunkIndex(3)+1)
|
||||
// first_epoch(1 + 1)
|
||||
// first_epoch(2)
|
||||
// 4
|
||||
// first_epoch(chunkIndex(startEpoch)+1)
|
||||
// first_epoch(chunkIndex(3)+1)
|
||||
// first_epoch(1 + 1)
|
||||
// first_epoch(2)
|
||||
// 4
|
||||
func (m *MaxSpanChunksSlice) NextChunkStartEpoch(startEpoch types.Epoch) types.Epoch {
|
||||
return m.params.firstEpoch(m.params.chunkIndex(startEpoch) + 1)
|
||||
}
|
||||
|
||||
@@ -72,11 +72,11 @@ func (s *Service) checkSlashableAttestations(
|
||||
// as the current epoch in time, we perform slashing detection.
|
||||
// The process is as follows given a list of attestations:
|
||||
//
|
||||
// 1. Check for attester double votes using the list of attestations.
|
||||
// 2. Group the attestations by chunk index.
|
||||
// 3. Update the min and max spans for those grouped attestations, check if any slashings are
|
||||
// found in the process
|
||||
// 4. Update the latest written epoch for all validators involved to the current epoch.
|
||||
// 1. Check for attester double votes using the list of attestations.
|
||||
// 2. Group the attestations by chunk index.
|
||||
// 3. Update the min and max spans for those grouped attestations, check if any slashings are
|
||||
// found in the process
|
||||
// 4. Update the latest written epoch for all validators involved to the current epoch.
|
||||
//
|
||||
// This function performs a lot of critical actions and is split into smaller helpers for cleanliness.
|
||||
func (s *Service) detectAllAttesterSlashings(
|
||||
@@ -239,13 +239,13 @@ func (s *Service) epochUpdateForValidator(
|
||||
}
|
||||
|
||||
// Updates spans and detects any slashable attester offenses along the way.
|
||||
// 1. Determine the chunks we need to use for updating for the validator indices
|
||||
// in a validator chunk index, then retrieve those chunks from the database.
|
||||
// 2. Using the chunks from step (1):
|
||||
// for every attestation by chunk index:
|
||||
// for each validator in the attestation's attesting indices:
|
||||
// - Check if the attestation is slashable, if so return a slashing object.
|
||||
// 3. Save the updated chunks to disk.
|
||||
// 1. Determine the chunks we need to use for updating for the validator indices
|
||||
// in a validator chunk index, then retrieve those chunks from the database.
|
||||
// 2. Using the chunks from step (1):
|
||||
// for every attestation by chunk index:
|
||||
// for each validator in the attestation's attesting indices:
|
||||
// - Check if the attestation is slashable, if so return a slashing object.
|
||||
// 3. Save the updated chunks to disk.
|
||||
func (s *Service) updateSpans(
|
||||
ctx context.Context,
|
||||
updatedChunks map[uint64]Chunker,
|
||||
|
||||
@@ -17,25 +17,25 @@
|
||||
// with length = H where H is the amount of epochs worth of history
|
||||
// we want to persist for slashing detection.
|
||||
//
|
||||
// validator_1_min_span = [2, 2, 2, ..., 2]
|
||||
// validator_1_max_span = [0, 0, 0, ..., 0]
|
||||
// validator_1_min_span = [2, 2, 2, ..., 2]
|
||||
// validator_1_max_span = [0, 0, 0, ..., 0]
|
||||
//
|
||||
// Instead of always dealing with length H arrays, which can be prohibitively
|
||||
// expensive to handle in memory, we split these arrays into chunks of length C.
|
||||
// For C = 3, for example, the 0th chunk of validator 1's min and max spans would look
|
||||
// as follows:
|
||||
//
|
||||
// validator_1_min_span_chunk_0 = [2, 2, 2]
|
||||
// validator_1_max_span_chunk_0 = [2, 2, 2]
|
||||
// validator_1_min_span_chunk_0 = [2, 2, 2]
|
||||
// validator_1_max_span_chunk_0 = [2, 2, 2]
|
||||
//
|
||||
// Next, on disk, we take chunks for K validators, and store them as flat slices.
|
||||
// For example, if H = 3, C = 3, and K = 3, then we can store 3 validators' chunks as a flat
|
||||
// slice as follows:
|
||||
//
|
||||
// val0 val1 val2
|
||||
// | | |
|
||||
// { } { } { }
|
||||
// [2, 2, 2, 2, 2, 2, 2, 2, 2]
|
||||
// val0 val1 val2
|
||||
// | | |
|
||||
// { } { } { }
|
||||
// [2, 2, 2, 2, 2, 2, 2, 2, 2]
|
||||
//
|
||||
// This is known as 2D chunking, pioneered by the Sigma Prime team here:
|
||||
// https://hackmd.io/@sproul/min-max-slasher. The parameters H, C, and K will be
|
||||
|
||||
@@ -44,10 +44,9 @@ func DefaultParams() *Parameters {
|
||||
// if we are keeping 6 epochs worth of data, and we have chunks of size 2, then epoch
|
||||
// 4 will fall into chunk index (4 % 6) / 2 = 2.
|
||||
//
|
||||
// span = [-, -, -, -, -, -]
|
||||
// chunked = [[-, -], [-, -], [-, -]]
|
||||
// |-> epoch 4, chunk idx 2
|
||||
//
|
||||
// span = [-, -, -, -, -, -]
|
||||
// chunked = [[-, -], [-, -], [-, -]]
|
||||
// |-> epoch 4, chunk idx 2
|
||||
func (p *Parameters) chunkIndex(epoch types.Epoch) uint64 {
|
||||
return uint64(epoch.Mod(uint64(p.historyLength)).Div(p.chunkSize))
|
||||
}
|
||||
@@ -63,12 +62,11 @@ func (p *Parameters) validatorChunkIndex(validatorIndex types.ValidatorIndex) ui
|
||||
// For example, if we have chunks of length 3 and we ask to give us the
|
||||
// first epoch of chunk1, then:
|
||||
//
|
||||
// chunk0 chunk1 chunk2
|
||||
// | | |
|
||||
// [[-, -, -], [-, -, -], [-, -, -], ...]
|
||||
// |
|
||||
// -> first epoch of chunk 1 equals 3
|
||||
//
|
||||
// chunk0 chunk1 chunk2
|
||||
// | | |
|
||||
// [[-, -, -], [-, -, -], [-, -, -], ...]
|
||||
// |
|
||||
// -> first epoch of chunk 1 equals 3
|
||||
func (p *Parameters) firstEpoch(chunkIndex uint64) types.Epoch {
|
||||
return types.Epoch(chunkIndex * p.chunkSize)
|
||||
}
|
||||
@@ -77,12 +75,11 @@ func (p *Parameters) firstEpoch(chunkIndex uint64) types.Epoch {
|
||||
// For example, if we have chunks of length 3 and we ask to give us the
|
||||
// last epoch of chunk1, then:
|
||||
//
|
||||
// chunk0 chunk1 chunk2
|
||||
// | | |
|
||||
// [[-, -, -], [-, -, -], [-, -, -], ...]
|
||||
// |
|
||||
// -> last epoch of chunk 1 equals 5
|
||||
//
|
||||
// chunk0 chunk1 chunk2
|
||||
// | | |
|
||||
// [[-, -, -], [-, -, -], [-, -, -], ...]
|
||||
// |
|
||||
// -> last epoch of chunk 1 equals 5
|
||||
func (p *Parameters) lastEpoch(chunkIndex uint64) types.Epoch {
|
||||
return p.firstEpoch(chunkIndex).Add(p.chunkSize - 1)
|
||||
}
|
||||
@@ -92,24 +89,23 @@ func (p *Parameters) lastEpoch(chunkIndex uint64) types.Epoch {
|
||||
// chunk of size C. For example, if C = 3 and K = 3, the data we store
|
||||
// on disk is a flat slice as follows:
|
||||
//
|
||||
// val0 val1 val2
|
||||
// | | |
|
||||
// { } { } { }
|
||||
// [-, -, -, -, -, -, -, -, -]
|
||||
// val0 val1 val2
|
||||
// | | |
|
||||
// { } { } { }
|
||||
// [-, -, -, -, -, -, -, -, -]
|
||||
//
|
||||
// Then, figuring out the exact cell index for epoch 1 for validator 2 is computed
|
||||
// with (validatorIndex % K)*C + (epoch % C), which gives us:
|
||||
//
|
||||
// (2 % 3)*3 + (1 % 3) =
|
||||
// (2*3) + (1) =
|
||||
// 7
|
||||
//
|
||||
// val0 val1 val2
|
||||
// | | |
|
||||
// { } { } { }
|
||||
// [-, -, -, -, -, -, -, -, -]
|
||||
// |-> epoch 1 for val2
|
||||
// (2 % 3)*3 + (1 % 3) =
|
||||
// (2*3) + (1) =
|
||||
// 7
|
||||
//
|
||||
// val0 val1 val2
|
||||
// | | |
|
||||
// { } { } { }
|
||||
// [-, -, -, -, -, -, -, -, -]
|
||||
// |-> epoch 1 for val2
|
||||
func (p *Parameters) cellIndex(validatorIndex types.ValidatorIndex, epoch types.Epoch) uint64 {
|
||||
validatorChunkOffset := p.validatorOffset(validatorIndex)
|
||||
chunkOffset := p.chunkOffset(epoch)
|
||||
@@ -134,17 +130,16 @@ func (p *Parameters) validatorOffset(validatorIndex types.ValidatorIndex) uint64
|
||||
// If chunkSize C = 3 and validatorChunkSize K = 3, and historyLength H = 12,
|
||||
// if we are looking for epoch 6 and validator 6, then
|
||||
//
|
||||
// validatorChunkIndex = 6 / 3 = 2
|
||||
// chunkIndex = (6 % historyLength) / 3 = (6 % 12) / 3 = 2
|
||||
// validatorChunkIndex = 6 / 3 = 2
|
||||
// chunkIndex = (6 % historyLength) / 3 = (6 % 12) / 3 = 2
|
||||
//
|
||||
// Then we compute how many chunks there are per max span, known as the "width"
|
||||
//
|
||||
// width = H / C = 12 / 3 = 4
|
||||
// width = H / C = 12 / 3 = 4
|
||||
//
|
||||
// So every span has 4 chunks. Then, we have a disk key calculated by
|
||||
//
|
||||
// validatorChunkIndex * width + chunkIndex = 2*4 + 2 = 10
|
||||
//
|
||||
// validatorChunkIndex * width + chunkIndex = 2*4 + 2 = 10
|
||||
func (p *Parameters) flatSliceID(validatorChunkIndex, chunkIndex uint64) []byte {
|
||||
width := p.historyLength.Div(p.chunkSize)
|
||||
return ssz.MarshalUint64(make([]byte, 0), uint64(width.Mul(validatorChunkIndex).Add(chunkIndex)))
|
||||
|
||||
Reference in New Issue
Block a user