Merge From Master (#2392)

This commit is contained in:
Nishant Das
2019-04-26 21:36:53 +08:00
committed by terence tsao
parent 6cdf27c356
commit 4318d21872
109 changed files with 2297 additions and 1236 deletions

69
.golangci.yml Normal file
View File

@@ -0,0 +1,69 @@
linters-settings:
govet:
check-shadowing: true
settings:
printf:
funcs:
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Infof
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf
golint:
min-confidence: 0
gocyclo:
min-complexity: 10
maligned:
suggest-new: true
dupl:
threshold: 100
goconst:
min-len: 2
min-occurrences: 2
depguard:
list-type: blacklist
packages:
# logging is allowed only by logutils.Log, logrus
# is allowed to use only in logutils package
- github.com/sirupsen/logrus
misspell:
locale: US
lll:
line-length: 140
goimports:
local-prefixes: github.com/golangci/golangci-lint
gocritic:
enabled-tags:
- performance
- style
- experimental
disabled-checks:
- wrapperFunc
linters:
enable:
- deadcode
- goconst
- goimports
- golint
- gosec
- misspell
- structcheck
- typecheck
- unparam
- varcheck
- gofmt
- unused
disable-all: true
run:
skip-dirs:
- proto/
- ^contracts/
deadline: 10m
# golangci.com configuration
# https://github.com/golangci/golangci/wiki/Configuration
service:
golangci-lint-version: 1.15.0 # use the fixed version to not introduce new linters unexpectedly
prepare:
- echo "here I can run custom commands, but no preparation needed for this repo"

View File

@@ -1,20 +0,0 @@
{
"Deadline": "10m",
"Exclude": [
"^proto/",
"^contracts/"
],
"DisableAll": true,
"Enable": [
"deadcode",
"goconst",
"goimports",
"golint",
"gosec",
"gotype",
"misspell",
"structcheck",
"unparam",
"varcheck"
]
}

View File

@@ -10,8 +10,9 @@ matrix:
- lint
install:
- go get ${gobuild_args} -t ./...
- go get ${gobuild_args} github.com/golangci/golangci-lint/cmd/golangci-lint
script:
- go get ${gobuild_args} github.com/alecthomas/gometalinter && gometalinter --install && gometalinter ./...
- golangci-lint run
email: false
after_success:
- wget https://raw.githubusercontent.com/k3rn31p4nic/travis-ci-discord-webhook/master/send.sh

View File

@@ -170,10 +170,10 @@ To run the unit tests of our system do:
bazel test //...
```
To run our linter, make sure you have [gometalinter](https://github.com/alecthomas/gometalinter) installed and then run:
To run our linter, make sure you have [golangci-lint](https://https://github.com/golangci/golangci-lint) installed and then run:
```
gometalinter ./...
golangci-lint run
```
# Contributing

View File

@@ -21,9 +21,9 @@ http_archive(
http_archive(
name = "com_github_atlassian_bazel_tools",
sha256 = "f4d370dec7316e668c015be86b05593a0a71fa3047108c445b6643cb954193f7",
strip_prefix = "bazel-tools-e31d79dc72434fe064b7df4efb51875b2c201e84",
urls = ["https://github.com/atlassian/bazel-tools/archive/e31d79dc72434fe064b7df4efb51875b2c201e84.tar.gz"],
sha256 = "af4908ea16b43e0c88007742a5c54997ee068fc393f9850ade2d59b1d5f49f55",
strip_prefix = "bazel-tools-31382b2267b0bc3d9771085e3503473a061593e1",
urls = ["https://github.com/atlassian/bazel-tools/archive/31382b2267b0bc3d9771085e3503473a061593e1.tar.gz"],
)
http_archive(
@@ -41,9 +41,9 @@ http_archive(
http_archive(
name = "io_bazel_rules_k8s",
sha256 = "f0a66b29bb6705da233899b61723d3fcc1b68d1e6414189a6f9c82795d407f27",
strip_prefix = "rules_k8s-50fb3c2f868fcd0b5c3f223ac19ba72db1f6eb7d",
url = "https://github.com/bazelbuild/rules_k8s/archive/50fb3c2f868fcd0b5c3f223ac19ba72db1f6eb7d.tar.gz",
sha256 = "b4aabc3f931a67b4970076ae9490afc18caa1690360c952fba9681225739f6d5",
strip_prefix = "rules_k8s-e7b408f07785e3b660ee7e99173b0e4328c7b65e",
url = "https://github.com/bazelbuild/rules_k8s/archive/e7b408f07785e3b660ee7e99173b0e4328c7b65e.tar.gz",
)
load(
@@ -182,7 +182,7 @@ go_repository(
go_repository(
name = "com_github_libp2p_go_libp2p",
commit = "f106bf7f74f573d33505b7173ef2f7f0596b5d67", # v0.0.13
commit = "5bce62bbecc0c07087af4cae2490b764afe1c594", # v0.0.15
importpath = "github.com/libp2p/go-libp2p",
)
@@ -213,7 +213,7 @@ go_repository(
go_repository(
name = "com_github_multiformats_go_multihash",
commit = "6b439b7c6e3c44c112171540500be697ba235235", # v0.0.1
commit = "922cbd7915f407488e3f4413ada76400a1b29b49", # v0.0.3
importpath = "github.com/multiformats/go-multihash",
)
@@ -632,6 +632,14 @@ go_repository(
importpath = "go.opencensus.io",
)
go_repository(
name = "io_opencensus_go_contrib_exporter_jaeger",
commit = "5b8293c22f362562285c2acbc52f4a1870a47a33",
importpath = "contrib.go.opencensus.io/exporter/jaeger",
remote = "http://github.com/census-ecosystem/opencensus-go-exporter-jaeger",
vcs = "git",
)
go_repository(
name = "org_golang_google_api",
commit = "0cbcb99a9ea0c8023c794b2693cbe1def82ed4d7", # v0.3.2
@@ -750,13 +758,13 @@ go_repository(
go_repository(
name = "com_github_libp2p_go_libp2p_kad_dht",
build_file_proto_mode = "disable_global",
commit = "b99a6ee931a8331ccfb8292bee6d3e5c03edf5e1", # v0.0.8
commit = "b220ac23e82c0df788178e806b1fefa92e936766", # v0.0.9
importpath = "github.com/libp2p/go-libp2p-kad-dht",
)
go_repository(
name = "com_github_ipfs_go_datastore",
commit = "80940bb93587a19603a74ea07f9e5c921bae3b07", # v0.0.4
commit = "f8bd98feaffb64c335ac5e74f0a3d3aedbfd13ba", # v0.0.5
importpath = "github.com/ipfs/go-datastore",
)
@@ -829,7 +837,7 @@ go_repository(
go_repository(
name = "com_github_libp2p_go_libp2p_discovery",
commit = "d4ef632c52ff995d94eaed926529eede8faa3965", # v0.0.1
commit = "4cb4193d603389a75bccd07336de74d54bea6b00", # v0.0.2
importpath = "github.com/libp2p/go-libp2p-discovery",
)
@@ -1064,3 +1072,9 @@ go_repository(
commit = "502116f1a0a0c1140aab04fd3787489209b357d3", # v1.2.0
importpath = "github.com/grpc-ecosystem/go-grpc-prometheus",
)
go_repository(
name = "com_github_karlseguin_ccache",
commit = "ec06cd93a07565b373789b0078ba88fe697fddd9",
importpath = "github.com/karlseguin/ccache",
)

View File

@@ -38,6 +38,8 @@ go_test(
"//shared/bytesutil:go_default_library",
"//shared/hashutil:go_default_library",
"//shared/params:go_default_library",
"//shared/testutil:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
"@com_github_sirupsen_logrus//hooks/test:go_default_library",
],
)

View File

@@ -4,6 +4,7 @@ package attestation
import (
"context"
"fmt"
"sort"
"sync"
"github.com/gogo/protobuf/proto"
@@ -86,55 +87,36 @@ func (a *Service) IncomingAttestationFeed() *event.Feed {
return a.incomingFeed
}
// LatestAttestation returns the latest attestation from validator index, the highest
// slotNumber attestation from the attestation pool gets returned.
//
// Spec pseudocode definition:
// Let `get_latest_attestation(store: Store, validator_index: ValidatorIndex) ->
// Attestation` be the attestation with the highest slot number in `store`
// from the validator with the given `validator_index`
func (a *Service) LatestAttestation(ctx context.Context, index uint64) (*pb.Attestation, error) {
validatorRegistry, err := a.beaconDB.ValidatorRegistry(ctx)
if err != nil {
return nil, err
}
// return error if it's an invalid validator index.
if index >= uint64(len(validatorRegistry)) {
return nil, fmt.Errorf("invalid validator index %d", index)
}
pubKey := bytesutil.ToBytes48(validatorRegistry[index].Pubkey)
a.store.RLock()
defer a.store.RUnlock()
if _, exists := a.store.m[pubKey]; !exists {
return nil, nil
}
return a.store.m[pubKey], nil
}
// LatestAttestationTarget returns the target block the validator index attested to,
// LatestAttestationTarget returns the target block that the validator index attested to,
// the highest slotNumber attestation in attestation pool gets returned.
//
// Spec pseudocode definition:
// Let `get_latest_attestation_target(store: Store, validator_index: ValidatorIndex) ->
// BeaconBlock` be the target block in the attestation
// `get_latest_attestation(store, validator_index)`.
func (a *Service) LatestAttestationTarget(ctx context.Context, index uint64) (*pb.BeaconBlock, error) {
attestation, err := a.LatestAttestation(ctx, index)
if err != nil {
return nil, fmt.Errorf("could not get attestation: %v", err)
func (a *Service) LatestAttestationTarget(beaconState *pb.BeaconState, index uint64) (*pb.AttestationTarget, error) {
if index >= uint64(len(beaconState.ValidatorRegistry)) {
return nil, fmt.Errorf("invalid validator index %d", index)
}
validator := beaconState.ValidatorRegistry[index]
pubKey := bytesutil.ToBytes48(validator.Pubkey)
a.store.RLock()
defer a.store.RUnlock()
if _, exists := a.store.m[pubKey]; !exists {
return nil, nil
}
attestation := a.store.m[pubKey]
if attestation == nil {
return nil, nil
}
targetBlockHash := bytesutil.ToBytes32(attestation.Data.BeaconBlockRootHash32)
targetBlock, err := a.beaconDB.Block(targetBlockHash)
if err != nil {
return nil, fmt.Errorf("could not get target block: %v", err)
targetRoot := bytesutil.ToBytes32(attestation.Data.BeaconBlockRootHash32)
if !a.beaconDB.HasBlock(targetRoot) {
return nil, nil
}
return targetBlock, nil
return a.beaconDB.AttestationTarget(targetRoot)
}
// attestationPool takes an newly received attestation from sync service
@@ -148,8 +130,8 @@ func (a *Service) attestationPool() {
log.Debug("Attestation pool closed, exiting goroutine")
return
// Listen for a newly received incoming attestation from the sync service.
case attestation := <-a.incomingChan:
handler.SafelyHandleMessage(a.ctx, a.handleAttestation, attestation)
case attestations := <-a.incomingChan:
handler.SafelyHandleMessage(a.ctx, a.handleAttestation, attestations)
}
}
}
@@ -183,10 +165,58 @@ func (a *Service) UpdateLatestAttestation(ctx context.Context, attestation *pb.A
if err != nil {
return err
}
return a.updateAttestation(ctx, headRoot, beaconState, attestation)
}
// BatchUpdateLatestAttestation updates multiple attestations and adds them into the attestation store
// if they are valid.
func (a *Service) BatchUpdateLatestAttestation(ctx context.Context, attestations []*pb.Attestation) error {
if attestations == nil {
return nil
}
// Potential improvement, instead of getting the state,
// we could get a mapping of validator index to public key.
beaconState, err := a.beaconDB.HeadState(ctx)
if err != nil {
return err
}
head, err := a.beaconDB.ChainHead()
if err != nil {
return err
}
headRoot, err := hashutil.HashBeaconBlock(head)
if err != nil {
return err
}
attestations = a.sortAttestations(attestations)
for _, attestation := range attestations {
if err := a.updateAttestation(ctx, headRoot, beaconState, attestation); err != nil {
return err
}
}
return nil
}
// InsertAttestationIntoStore locks the store, inserts the attestation, then
// unlocks the store again. This method may be used by external services
// in testing to populate the attestation store.
func (a *Service) InsertAttestationIntoStore(pubkey [48]byte, att *pb.Attestation) {
a.store.Lock()
defer a.store.Unlock()
a.store.m[pubkey] = att
}
func (a *Service) updateAttestation(ctx context.Context, headRoot [32]byte, beaconState *pb.BeaconState,
attestation *pb.Attestation) error {
totalAttestationSeen.Inc()
slot := attestation.Data.Slot
var committee []uint64
var cachedCommittees *cache.CommitteesInSlot
var err error
for beaconState.Slot < slot {
beaconState, err = state.ExecuteStateTransition(
@@ -245,6 +275,15 @@ func (a *Service) UpdateLatestAttestation(ctx context.Context, attestation *pb.A
continue
}
if i >= len(committee) {
log.Errorf("Bitfield points to an invalid index in the committee: bitfield %08b", bitfield)
continue
}
if int(committee[i]) >= len(beaconState.ValidatorRegistry) {
log.Errorf("Index doesn't exist in validator registry: index %d", committee[i])
}
// If the attestation came from this attester. We use the slot committee to find the
// validator's actual index.
pubkey := bytesutil.ToBytes48(beaconState.ValidatorRegistry[committee[i]].Pubkey)
@@ -277,11 +316,11 @@ func (a *Service) UpdateLatestAttestation(ctx context.Context, attestation *pb.A
return nil
}
// InsertAttestationIntoStore locks the store, inserts the attestation, then
// unlocks the store again. This method may be used by external services
// in testing to populate the attestation store.
func (a *Service) InsertAttestationIntoStore(pubkey [48]byte, att *pb.Attestation) {
a.store.Lock()
defer a.store.Unlock()
a.store.m[pubkey] = att
// sortAttestations sorts attestations by their slot number in ascending order.
func (a *Service) sortAttestations(attestations []*pb.Attestation) []*pb.Attestation {
sort.SliceStable(attestations, func(i, j int) bool {
return attestations[i].Data.Slot < attestations[j].Data.Slot
})
return attestations
}

View File

@@ -1,6 +1,7 @@
package attestation
import (
"bytes"
"context"
"fmt"
"reflect"
@@ -13,7 +14,9 @@ import (
"github.com/prysmaticlabs/prysm/shared/bytesutil"
"github.com/prysmaticlabs/prysm/shared/hashutil"
"github.com/prysmaticlabs/prysm/shared/params"
"github.com/prysmaticlabs/prysm/shared/testutil"
"github.com/sirupsen/logrus"
logTest "github.com/sirupsen/logrus/hooks/test"
)
func init() {
@@ -128,73 +131,6 @@ func TestAttestationPool_UpdatesAttestationPool(t *testing.T) {
}
}
func TestLatestAttestation_ReturnsLatestAttestation(t *testing.T) {
beaconDB := internal.SetupDB(t)
defer internal.TeardownDB(t, beaconDB)
ctx := context.Background()
pubKey := []byte{'A'}
if err := beaconDB.SaveState(ctx, &pb.BeaconState{
ValidatorRegistry: []*pb.Validator{{Pubkey: pubKey}},
}); err != nil {
t.Fatalf("could not save state: %v", err)
}
service := NewAttestationService(context.Background(), &Config{BeaconDB: beaconDB})
pubKey48 := bytesutil.ToBytes48(pubKey)
attestation := &pb.Attestation{AggregationBitfield: []byte{'B'}}
service.store.m[pubKey48] = attestation
latestAttestation, err := service.LatestAttestation(ctx, 0)
if err != nil {
t.Fatalf("Could not get latest attestation: %v", err)
}
if !reflect.DeepEqual(attestation, latestAttestation) {
t.Errorf("Wanted: %v, got: %v", attestation, latestAttestation)
}
}
func TestLatestAttestation_InvalidIndex(t *testing.T) {
beaconDB := internal.SetupDB(t)
defer internal.TeardownDB(t, beaconDB)
ctx := context.Background()
if err := beaconDB.SaveState(ctx, &pb.BeaconState{
ValidatorRegistry: []*pb.Validator{},
}); err != nil {
t.Fatalf("could not save state: %v", err)
}
service := NewAttestationService(context.Background(), &Config{BeaconDB: beaconDB})
index := uint64(0)
want := fmt.Sprintf("invalid validator index %d", index)
if _, err := service.LatestAttestation(ctx, index); !strings.Contains(err.Error(), want) {
t.Errorf("Wanted error to contain %s, received %v", want, err)
}
}
func TestLatestAttestation_NoAttestation(t *testing.T) {
beaconDB := internal.SetupDB(t)
defer internal.TeardownDB(t, beaconDB)
ctx := context.Background()
if err := beaconDB.SaveState(ctx, &pb.BeaconState{
ValidatorRegistry: []*pb.Validator{{}},
}); err != nil {
t.Fatalf("could not save state: %v", err)
}
service := NewAttestationService(context.Background(), &Config{BeaconDB: beaconDB})
index := 0
a, err := service.LatestAttestation(ctx, uint64(index))
if err != nil {
t.Fatalf("could not run latest attestation: %v", err)
}
if a != nil {
t.Errorf("Wanted attesstation %v, received %v", nil, a)
}
}
func TestLatestAttestationTarget_CantGetAttestation(t *testing.T) {
beaconDB := internal.SetupDB(t)
defer internal.TeardownDB(t, beaconDB)
@@ -206,10 +142,14 @@ func TestLatestAttestationTarget_CantGetAttestation(t *testing.T) {
t.Fatalf("could not save state: %v", err)
}
service := NewAttestationService(context.Background(), &Config{BeaconDB: beaconDB})
headState, err := beaconDB.HeadState(ctx)
if err != nil {
t.Fatal(err)
}
index := uint64(100)
want := fmt.Sprintf("could not get attestation: invalid validator index %d", index)
if _, err := service.LatestAttestationTarget(ctx, index); !strings.Contains(err.Error(), want) {
want := fmt.Sprintf("invalid validator index %d", index)
if _, err := service.LatestAttestationTarget(headState, index); !strings.Contains(err.Error(), want) {
t.Errorf("Wanted error to contain %s, received %v", want, err)
}
}
@@ -234,6 +174,13 @@ func TestLatestAttestationTarget_ReturnsLatestAttestedBlock(t *testing.T) {
if err != nil {
log.Fatalf("could not hash block: %v", err)
}
if err := beaconDB.SaveAttestationTarget(ctx, &pb.AttestationTarget{
Slot: block.Slot,
BlockRoot: blockRoot[:],
ParentRoot: []byte{},
}); err != nil {
log.Fatalf("could not save att target: %v", err)
}
service := NewAttestationService(context.Background(), &Config{BeaconDB: beaconDB})
@@ -244,12 +191,18 @@ func TestLatestAttestationTarget_ReturnsLatestAttestedBlock(t *testing.T) {
pubKey48 := bytesutil.ToBytes48(pubKey)
service.store.m[pubKey48] = attestation
latestAttestedBlock, err := service.LatestAttestationTarget(ctx, 0)
headState, err := beaconDB.HeadState(ctx)
if err != nil {
t.Fatal(err)
}
latestAttestedTarget, err := service.LatestAttestationTarget(headState, 0)
if err != nil {
t.Fatalf("Could not get latest attestation: %v", err)
}
if !reflect.DeepEqual(block, latestAttestedBlock) {
t.Errorf("Wanted: %v, got: %v", block, latestAttestedBlock)
if !bytes.Equal(blockRoot[:], latestAttestedTarget.BlockRoot) {
t.Errorf("Wanted: %v, got: %v", blockRoot[:], latestAttestedTarget.BlockRoot)
}
}
@@ -402,3 +355,90 @@ func TestUpdateLatestAttestation_CacheEnabledAndHit(t *testing.T) {
attestation.Data.Slot, service.store.m[pubkey].Data.Slot)
}
}
func TestUpdateLatestAttestation_InvalidIndex(t *testing.T) {
beaconDB := internal.SetupDB(t)
hook := logTest.NewGlobal()
defer internal.TeardownDB(t, beaconDB)
ctx := context.Background()
var validators []*pb.Validator
for i := 0; i < 64; i++ {
validators = append(validators, &pb.Validator{
Pubkey: []byte{byte(i)},
ActivationEpoch: params.BeaconConfig().GenesisEpoch,
ExitEpoch: params.BeaconConfig().GenesisEpoch + 10,
})
}
beaconState := &pb.BeaconState{
Slot: params.BeaconConfig().GenesisSlot + 1,
ValidatorRegistry: validators,
}
block := &pb.BeaconBlock{
Slot: params.BeaconConfig().GenesisSlot + 1,
}
if err := beaconDB.SaveBlock(block); err != nil {
t.Fatal(err)
}
if err := beaconDB.UpdateChainHead(ctx, block, beaconState); err != nil {
t.Fatal(err)
}
service := NewAttestationService(context.Background(), &Config{BeaconDB: beaconDB})
attestation := &pb.Attestation{
AggregationBitfield: []byte{0xC0},
Data: &pb.AttestationData{
Slot: params.BeaconConfig().GenesisSlot + 1,
Shard: 1,
},
}
if err := service.UpdateLatestAttestation(ctx, attestation); err != nil {
t.Fatalf("could not update latest attestation: %v", err)
}
testutil.AssertLogsContain(t, hook, "Bitfield points to an invalid index in the committee")
}
func TestUpdateLatestAttestation_BatchUpdate(t *testing.T) {
beaconDB := internal.SetupDB(t)
defer internal.TeardownDB(t, beaconDB)
ctx := context.Background()
var validators []*pb.Validator
for i := 0; i < 64; i++ {
validators = append(validators, &pb.Validator{
Pubkey: []byte{byte(i)},
ActivationEpoch: params.BeaconConfig().GenesisEpoch,
ExitEpoch: params.BeaconConfig().GenesisEpoch + 10,
})
}
beaconState := &pb.BeaconState{
Slot: params.BeaconConfig().GenesisSlot + 1,
ValidatorRegistry: validators,
}
block := &pb.BeaconBlock{
Slot: params.BeaconConfig().GenesisSlot + 1,
}
if err := beaconDB.SaveBlock(block); err != nil {
t.Fatal(err)
}
if err := beaconDB.UpdateChainHead(ctx, block, beaconState); err != nil {
t.Fatal(err)
}
service := NewAttestationService(context.Background(), &Config{BeaconDB: beaconDB})
attestations := make([]*pb.Attestation, 0)
for i := 0; i < 10; i++ {
attestations = append(attestations, &pb.Attestation{
AggregationBitfield: []byte{0x80},
Data: &pb.AttestationData{
Slot: params.BeaconConfig().GenesisSlot + 1,
Shard: 1,
},
})
}
if err := service.BatchUpdateLatestAttestation(ctx, attestations); err != nil {
t.Fatalf("could not update latest attestation: %v", err)
}
}

View File

@@ -26,7 +26,6 @@ go_library(
"//shared/hashutil:go_default_library",
"//shared/p2p:go_default_library",
"//shared/params:go_default_library",
"@com_github_gogo_protobuf//proto:go_default_library",
"@com_github_prometheus_client_golang//prometheus:go_default_library",
"@com_github_prometheus_client_golang//prometheus/promauto:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",

View File

@@ -54,6 +54,8 @@ func (b *BlockFailedProcessingErr) Error() string {
// 4. Process and cleanup any block operations, such as attestations and deposits, which would need to be
// either included or flushed from the beacon node's runtime.
func (c *ChainService) ReceiveBlock(ctx context.Context, block *pb.BeaconBlock) (*pb.BeaconState, error) {
c.receiveBlockLock.Lock()
defer c.receiveBlockLock.Unlock()
ctx, span := trace.StartSpan(ctx, "beacon-chain.blockchain.ReceiveBlock")
defer span.End()
parentRoot := bytesutil.ToBytes32(block.ParentRootHash32)
@@ -215,6 +217,13 @@ func (c *ChainService) SaveAndBroadcastBlock(ctx context.Context, block *pb.Beac
if err := c.beaconDB.SaveBlock(block); err != nil {
return fmt.Errorf("failed to save block: %v", err)
}
if err := c.beaconDB.SaveAttestationTarget(ctx, &pb.AttestationTarget{
Slot: block.Slot,
BlockRoot: blockRoot[:],
ParentRoot: block.ParentRootHash32,
}); err != nil {
return fmt.Errorf("failed to save attestation target: %v", err)
}
// Announce the new block to the network.
c.p2p.Broadcast(ctx, &pb.BeaconBlockAnnounce{
Hash: blockRoot[:],
@@ -233,11 +242,8 @@ func (c *ChainService) CleanupBlockOperations(ctx context.Context, block *pb.Bea
log.Error("Sent processed block to no subscribers")
}
// Update attestation store with latest attestation target.
for _, att := range block.Body.Attestations {
if err := c.attsService.UpdateLatestAttestation(ctx, att); err != nil {
return fmt.Errorf("failed to update latest attestation for store: %v", err)
}
if err := c.attsService.BatchUpdateLatestAttestation(ctx, block.Body.Attestations); err != nil {
return fmt.Errorf("failed to update latest attestation for store: %v", err)
}
// Remove pending deposits from the deposit queue.

View File

@@ -192,7 +192,7 @@ func TestReceiveBlock_UsesParentBlockState(t *testing.T) {
t.Fatalf("Could not tree hash state: %v", err)
}
parentHash, genesisBlock := setupGenesisBlock(t, chainService, beaconState)
parentHash, genesisBlock := setupGenesisBlock(t, chainService)
if err := chainService.beaconDB.UpdateChainHead(ctx, genesisBlock, beaconState); err != nil {
t.Fatal(err)
}
@@ -247,7 +247,7 @@ func TestReceiveBlock_DeletesBadBlock(t *testing.T) {
t.Fatal(err)
}
parentHash, genesisBlock := setupGenesisBlock(t, chainService, beaconState)
parentHash, genesisBlock := setupGenesisBlock(t, chainService)
if err := chainService.beaconDB.UpdateChainHead(ctx, genesisBlock, beaconState); err != nil {
t.Fatal(err)
}
@@ -325,7 +325,7 @@ func TestReceiveBlock_CheckBlockStateRoot_GoodState(t *testing.T) {
if err := chainService.beaconDB.SaveHistoricalState(ctx, beaconState); err != nil {
t.Fatal(err)
}
parentHash, genesisBlock := setupGenesisBlock(t, chainService, beaconState)
parentHash, genesisBlock := setupGenesisBlock(t, chainService)
beaconState.Slot++
if err := chainService.beaconDB.UpdateChainHead(ctx, genesisBlock, beaconState); err != nil {
t.Fatal(err)
@@ -370,7 +370,7 @@ func TestReceiveBlock_CheckBlockStateRoot_BadState(t *testing.T) {
if err := chainService.beaconDB.SaveHistoricalState(ctx, beaconState); err != nil {
t.Fatal(err)
}
parentHash, genesisBlock := setupGenesisBlock(t, chainService, beaconState)
parentHash, genesisBlock := setupGenesisBlock(t, chainService)
beaconState.Slot++
if err := chainService.beaconDB.UpdateChainHead(ctx, genesisBlock, beaconState); err != nil {
t.Fatal(err)
@@ -426,7 +426,7 @@ func TestReceiveBlock_RemovesPendingDeposits(t *testing.T) {
if err != nil {
t.Fatalf("Could not tree hash state: %v", err)
}
parentHash, genesisBlock := setupGenesisBlock(t, chainService, beaconState)
parentHash, genesisBlock := setupGenesisBlock(t, chainService)
beaconState.Slot++
if err := chainService.beaconDB.UpdateChainHead(ctx, genesisBlock, beaconState); err != nil {
t.Fatal(err)
@@ -581,7 +581,7 @@ func TestReceiveBlock_OnChainSplit(t *testing.T) {
if err != nil {
t.Fatalf("Could not tree hash state: %v", err)
}
parentHash, genesisBlock := setupGenesisBlock(t, chainService, beaconState)
parentHash, genesisBlock := setupGenesisBlock(t, chainService)
if err := db.UpdateChainHead(ctx, genesisBlock, beaconState); err != nil {
t.Fatal(err)
}

View File

@@ -1,10 +1,10 @@
package blockchain
import (
"bytes"
"context"
"fmt"
"github.com/gogo/protobuf/proto"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
"github.com/prysmaticlabs/prysm/beacon-chain/cache"
@@ -12,9 +12,9 @@ import (
"github.com/prysmaticlabs/prysm/beacon-chain/db"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared/bytesutil"
"github.com/prysmaticlabs/prysm/shared/featureconfig"
"github.com/prysmaticlabs/prysm/shared/hashutil"
"github.com/prysmaticlabs/prysm/shared/params"
"github.com/sirupsen/logrus"
"go.opencensus.io/trace"
)
@@ -132,7 +132,7 @@ func (c *ChainService) ApplyForkChoiceRule(
if err != nil {
return fmt.Errorf("could not retrieve justified state: %v", err)
}
attestationTargets, err := c.attestationTargets(ctx, justifiedState)
attestationTargets, err := c.attestationTargets(justifiedState)
if err != nil {
return fmt.Errorf("could not retrieve attestation target: %v", err)
}
@@ -181,7 +181,9 @@ func (c *ChainService) ApplyForkChoiceRule(
if err != nil {
return fmt.Errorf("could not hash head: %v", err)
}
log.WithField("headRoot", fmt.Sprintf("0x%x", h)).Info("Chain head block and state updated")
log.WithFields(logrus.Fields{
"headRoot": fmt.Sprintf("0x%x", h),
}).Info("Chain head block and state updated")
return nil
}
@@ -217,10 +219,9 @@ func (c *ChainService) lmdGhost(
ctx context.Context,
startBlock *pb.BeaconBlock,
startState *pb.BeaconState,
voteTargets map[uint64]*pb.BeaconBlock,
voteTargets map[uint64]*pb.AttestationTarget,
) (*pb.BeaconBlock, error) {
highestSlot := c.beaconDB.HighestBlockSlot()
head := startBlock
for {
children, err := c.blockChildren(ctx, head, highestSlot)
@@ -290,18 +291,18 @@ func (c *ChainService) blockChildren(ctx context.Context, block *pb.BeaconBlock,
// attestationTargets retrieves the list of attestation targets since last finalized epoch,
// each attestation target consists of validator index and its attestation target (i.e. the block
// which the validator attested to)
func (c *ChainService) attestationTargets(ctx context.Context, state *pb.BeaconState) (map[uint64]*pb.BeaconBlock, error) {
func (c *ChainService) attestationTargets(state *pb.BeaconState) (map[uint64]*pb.AttestationTarget, error) {
indices := helpers.ActiveValidatorIndices(state, helpers.CurrentEpoch(state))
attestationTargets := make(map[uint64]*pb.BeaconBlock)
attestationTargets := make(map[uint64]*pb.AttestationTarget)
for i, index := range indices {
block, err := c.attsService.LatestAttestationTarget(ctx, index)
target, err := c.attsService.LatestAttestationTarget(state, index)
if err != nil {
return nil, fmt.Errorf("could not retrieve attestation target: %v", err)
}
if block == nil {
if target == nil {
continue
}
attestationTargets[uint64(i)] = block
attestationTargets[uint64(i)] = target
}
return attestationTargets, nil
}
@@ -316,34 +317,31 @@ func (c *ChainService) attestationTargets(ctx context.Context, state *pb.BeaconS
// for validator_index, target in attestation_targets
// if get_ancestor(store, target, block.slot) == block
// )
func VoteCount(block *pb.BeaconBlock, state *pb.BeaconState, targets map[uint64]*pb.BeaconBlock, beaconDB *db.BeaconDB) (int, error) {
func VoteCount(block *pb.BeaconBlock, state *pb.BeaconState, targets map[uint64]*pb.AttestationTarget, beaconDB *db.BeaconDB) (int, error) {
balances := 0
var ancestor *pb.BeaconBlock
var ancestorRoot []byte
var err error
for validatorIndex, targetBlock := range targets {
if featureconfig.FeatureConfig().EnableBlockAncestorCache {
ancestor, err = cachedAncestorBlock(targetBlock, block.Slot, beaconDB)
if err != nil {
return 0, err
}
} else {
// if block ancestor cache was not enabled, retrieve the ancestor recursively.
ancestor, err = BlockAncestor(targetBlock, block.Slot, beaconDB)
if err != nil {
return 0, err
}
blockRoot, err := hashutil.HashBeaconBlock(block)
if err != nil {
return 0, err
}
for validatorIndex, target := range targets {
ancestorRoot, err = cachedAncestor(target, block.Slot, beaconDB)
if err != nil {
return 0, err
}
// This covers the following case, we start at B5, and want to process B6 and B7
// B6 can be processed, B7 can not be processed because it's pointed to the
// block older than current block 5.
// B4 - B5 - B6
// \ - - - - - B7
if ancestor == nil {
if ancestorRoot == nil {
continue
}
if proto.Equal(ancestor, block) {
if bytes.Equal(blockRoot[:], ancestorRoot) {
balances += int(helpers.EffectiveBalance(state, validatorIndex))
}
}
@@ -363,53 +361,63 @@ func VoteCount(block *pb.BeaconBlock, state *pb.BeaconState, targets map[uint64]
// return None
// else:
// return get_ancestor(store, store.get_parent(block), slot)
func BlockAncestor(block *pb.BeaconBlock, slot uint64, beaconDB *db.BeaconDB) (*pb.BeaconBlock, error) {
if block.Slot == slot {
return block, nil
func BlockAncestor(targetBlock *pb.AttestationTarget, slot uint64, beaconDB *db.BeaconDB) ([]byte, error) {
if targetBlock.Slot == slot {
return targetBlock.BlockRoot[:], nil
}
if block.Slot < slot {
if targetBlock.Slot < slot {
return nil, nil
}
parentHash := bytesutil.ToBytes32(block.ParentRootHash32)
parent, err := beaconDB.Block(parentHash)
parentRoot := bytesutil.ToBytes32(targetBlock.ParentRoot)
parent, err := beaconDB.Block(parentRoot)
if err != nil {
return nil, fmt.Errorf("could not get parent block: %v", err)
}
if parent == nil {
return nil, fmt.Errorf("parent block does not exist: %v", err)
}
return BlockAncestor(parent, slot, beaconDB)
newTarget := &pb.AttestationTarget{
Slot: parent.Slot,
BlockRoot: parentRoot[:],
ParentRoot: parent.ParentRootHash32,
}
return BlockAncestor(newTarget, slot, beaconDB)
}
// cachedAncestorBlock retrieves the cached ancestor block from block ancestor cache,
// cachedAncestor retrieves the cached ancestor target from block ancestor cache,
// if it's not there it looks up the block tree get it and cache it.
func cachedAncestorBlock(targetBlk *pb.BeaconBlock, height uint64, beaconDB *db.BeaconDB) (*pb.BeaconBlock, error) {
var ancestor *pb.BeaconBlock
func cachedAncestor(target *pb.AttestationTarget, height uint64, beaconDB *db.BeaconDB) ([]byte, error) {
// check if the ancestor block of from a given block height was cached.
targetHash, err := hashutil.HashBeaconBlock(targetBlk)
if err != nil {
return nil, err
}
cachedAncestorBlock, err := blkAncestorCache.AncestorBySlot(targetHash[:], height)
cachedAncestorInfo, err := blkAncestorCache.AncestorBySlot(target.BlockRoot, height)
if err != nil {
return nil, nil
}
if cachedAncestorBlock != nil {
return cachedAncestorBlock.Block, nil
if cachedAncestorInfo != nil {
return cachedAncestorInfo.Target.BlockRoot, nil
}
// add the ancestor to the cache if it was not cached.
ancestor, err = BlockAncestor(targetBlk, height, beaconDB)
ancestorRoot, err := BlockAncestor(target, height, beaconDB)
if err != nil {
return nil, err
}
ancestor, err := beaconDB.Block(bytesutil.ToBytes32(ancestorRoot))
if err != nil {
return nil, err
}
if ancestor == nil {
return nil, nil
}
ancestorTarget := &pb.AttestationTarget{
Slot: ancestor.Slot,
BlockRoot: ancestorRoot,
ParentRoot: ancestor.ParentRootHash32,
}
if err := blkAncestorCache.AddBlockAncestor(&cache.AncestorInfo{
Hash: targetHash[:],
Height: height,
Block: ancestor,
Hash: target.BlockRoot,
Target: ancestorTarget,
}); err != nil {
return nil, err
}
return ancestor, nil
return ancestorRoot, nil
}

View File

@@ -20,7 +20,6 @@ import (
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared/bls"
"github.com/prysmaticlabs/prysm/shared/bytesutil"
"github.com/prysmaticlabs/prysm/shared/featureconfig"
"github.com/prysmaticlabs/prysm/shared/forkutil"
"github.com/prysmaticlabs/prysm/shared/hashutil"
"github.com/prysmaticlabs/prysm/shared/params"
@@ -30,6 +29,7 @@ import (
// Ensure ChainService implements interfaces.
var _ = ForkChoice(&ChainService{})
var endpoint = "ws://127.0.0.1"
func TestApplyForkChoice_SetsCanonicalHead(t *testing.T) {
deposits, _ := setupInitialDeposits(t, 5)
@@ -140,9 +140,17 @@ func TestVoteCount_ParentDoesNotExistNoVoteCount(t *testing.T) {
if err := beaconDB.SaveBlock(potentialHead); err != nil {
t.Fatal(err)
}
headRoot, err := hashutil.HashBeaconBlock(potentialHead)
if err != nil {
t.Fatal(err)
}
voteTargets := make(map[uint64]*pb.BeaconBlock)
voteTargets[0] = potentialHead
voteTargets := make(map[uint64]*pb.AttestationTarget)
voteTargets[0] = &pb.AttestationTarget{
Slot: potentialHead.Slot,
BlockRoot: headRoot[:],
ParentRoot: potentialHead.ParentRootHash32,
}
count, err := VoteCount(genesisBlock, &pb.BeaconState{}, voteTargets, beaconDB)
if err != nil {
t.Fatalf("Could not get vote count: %v", err)
@@ -168,10 +176,19 @@ func TestVoteCount_IncreaseCountCorrectly(t *testing.T) {
Slot: params.BeaconConfig().GenesisSlot + 5,
ParentRootHash32: genesisRoot[:],
}
headRoot1, err := hashutil.HashBeaconBlock(potentialHead)
if err != nil {
t.Fatal(err)
}
potentialHead2 := &pb.BeaconBlock{
Slot: params.BeaconConfig().GenesisSlot + 6,
ParentRootHash32: genesisRoot[:],
}
headRoot2, err := hashutil.HashBeaconBlock(potentialHead2)
if err != nil {
t.Fatal(err)
}
// We store these potential heads in the DB.
if err := beaconDB.SaveBlock(potentialHead); err != nil {
t.Fatal(err)
@@ -180,9 +197,17 @@ func TestVoteCount_IncreaseCountCorrectly(t *testing.T) {
t.Fatal(err)
}
beaconState := &pb.BeaconState{Balances: []uint64{1e9, 1e9}}
voteTargets := make(map[uint64]*pb.BeaconBlock)
voteTargets[0] = potentialHead
voteTargets[1] = potentialHead2
voteTargets := make(map[uint64]*pb.AttestationTarget)
voteTargets[0] = &pb.AttestationTarget{
Slot: potentialHead.Slot,
BlockRoot: headRoot1[:],
ParentRoot: potentialHead.ParentRootHash32,
}
voteTargets[1] = &pb.AttestationTarget{
Slot: potentialHead2.Slot,
BlockRoot: headRoot2[:],
ParentRoot: potentialHead2.ParentRootHash32,
}
count, err := VoteCount(genesisBlock, beaconState, voteTargets, beaconDB)
if err != nil {
t.Fatalf("Could not fetch vote balances: %v", err)
@@ -216,6 +241,13 @@ func TestAttestationTargets_RetrieveWorks(t *testing.T) {
if err != nil {
log.Fatalf("could not hash block: %v", err)
}
if err := beaconDB.SaveAttestationTarget(ctx, &pb.AttestationTarget{
Slot: block.Slot,
BlockRoot: blockRoot[:],
ParentRoot: []byte{},
}); err != nil {
log.Fatalf("could not save att tgt: %v", err)
}
attsService := attestation.NewAttestationService(
context.Background(),
@@ -229,7 +261,7 @@ func TestAttestationTargets_RetrieveWorks(t *testing.T) {
attsService.InsertAttestationIntoStore(pubKey48, att)
chainService := setupBeaconChain(t, beaconDB, attsService)
attestationTargets, err := chainService.attestationTargets(ctx, beaconState)
attestationTargets, err := chainService.attestationTargets(beaconState)
if err != nil {
t.Fatalf("Could not get attestation targets: %v", err)
}
@@ -479,6 +511,10 @@ func TestLMDGhost_TrivialHeadUpdate(t *testing.T) {
Slot: 2,
ParentRootHash32: root1[:],
}
block2Root, err := hashutil.HashBeaconBlock(block2)
if err != nil {
t.Fatal(err)
}
if err = chainService.beaconDB.SaveBlock(block2); err != nil {
t.Fatalf("Could not save block: %v", err)
}
@@ -487,8 +523,12 @@ func TestLMDGhost_TrivialHeadUpdate(t *testing.T) {
}
// The only vote is on block 2.
voteTargets := make(map[uint64]*pb.BeaconBlock)
voteTargets[0] = block2
voteTargets := make(map[uint64]*pb.AttestationTarget)
voteTargets[0] = &pb.AttestationTarget{
Slot: block2.Slot,
BlockRoot: block2Root[:],
ParentRoot: block2.ParentRootHash32,
}
// LMDGhost should pick block 2.
head, err := chainService.lmdGhost(ctx, block1, beaconState, voteTargets)
@@ -540,6 +580,10 @@ func TestLMDGhost_3WayChainSplitsSameHeight(t *testing.T) {
Slot: 2,
ParentRootHash32: root1[:],
}
root2, err := hashutil.HashBeaconBlock(block2)
if err != nil {
t.Fatalf("Could not hash block: %v", err)
}
if err = chainService.beaconDB.SaveBlock(block2); err != nil {
t.Fatalf("Could not save block: %v", err)
}
@@ -551,6 +595,10 @@ func TestLMDGhost_3WayChainSplitsSameHeight(t *testing.T) {
Slot: 3,
ParentRootHash32: root1[:],
}
root3, err := hashutil.HashBeaconBlock(block3)
if err != nil {
t.Fatalf("Could not hash block: %v", err)
}
if err = chainService.beaconDB.SaveBlock(block3); err != nil {
t.Fatalf("Could not save block: %v", err)
}
@@ -562,6 +610,10 @@ func TestLMDGhost_3WayChainSplitsSameHeight(t *testing.T) {
Slot: 4,
ParentRootHash32: root1[:],
}
root4, err := hashutil.HashBeaconBlock(block4)
if err != nil {
t.Fatalf("Could not hash block: %v", err)
}
if err = chainService.beaconDB.SaveBlock(block4); err != nil {
t.Fatalf("Could not save block: %v", err)
}
@@ -570,11 +622,27 @@ func TestLMDGhost_3WayChainSplitsSameHeight(t *testing.T) {
}
// Give block 4 the most votes (2).
voteTargets := make(map[uint64]*pb.BeaconBlock)
voteTargets[0] = block2
voteTargets[1] = block3
voteTargets[2] = block4
voteTargets[3] = block4
voteTargets := make(map[uint64]*pb.AttestationTarget)
voteTargets[0] = &pb.AttestationTarget{
Slot: block2.Slot,
BlockRoot: root2[:],
ParentRoot: block2.ParentRootHash32,
}
voteTargets[1] = &pb.AttestationTarget{
Slot: block3.Slot,
BlockRoot: root3[:],
ParentRoot: block3.ParentRootHash32,
}
voteTargets[2] = &pb.AttestationTarget{
Slot: block4.Slot,
BlockRoot: root4[:],
ParentRoot: block4.ParentRootHash32,
}
voteTargets[3] = &pb.AttestationTarget{
Slot: block4.Slot,
BlockRoot: root4[:],
ParentRoot: block4.ParentRootHash32,
}
// LMDGhost should pick block 4.
head, err := chainService.lmdGhost(ctx, block1, beaconState, voteTargets)
if err != nil {
@@ -669,6 +737,10 @@ func TestLMDGhost_2WayChainSplitsDiffHeight(t *testing.T) {
Slot: 5,
ParentRootHash32: root3[:],
}
root5, err := hashutil.HashBeaconBlock(block5)
if err != nil {
t.Fatalf("Could not hash block: %v", err)
}
if err = chainService.beaconDB.SaveBlock(block5); err != nil {
t.Fatalf("Could not save block: %v", err)
}
@@ -680,6 +752,10 @@ func TestLMDGhost_2WayChainSplitsDiffHeight(t *testing.T) {
Slot: 6,
ParentRootHash32: root4[:],
}
root6, err := hashutil.HashBeaconBlock(block6)
if err != nil {
t.Fatalf("Could not hash block: %v", err)
}
if err = chainService.beaconDB.SaveBlock(block6); err != nil {
t.Fatalf("Could not save block: %v", err)
}
@@ -688,10 +764,22 @@ func TestLMDGhost_2WayChainSplitsDiffHeight(t *testing.T) {
}
// Give block 5 the most votes (2).
voteTargets := make(map[uint64]*pb.BeaconBlock)
voteTargets[0] = block6
voteTargets[1] = block5
voteTargets[2] = block5
voteTargets := make(map[uint64]*pb.AttestationTarget)
voteTargets[0] = &pb.AttestationTarget{
Slot: block6.Slot,
BlockRoot: root6[:],
ParentRoot: block6.ParentRootHash32,
}
voteTargets[1] = &pb.AttestationTarget{
Slot: block5.Slot,
BlockRoot: root5[:],
ParentRoot: block5.ParentRootHash32,
}
voteTargets[2] = &pb.AttestationTarget{
Slot: block5.Slot,
BlockRoot: root5[:],
ParentRoot: block5.ParentRootHash32,
}
// LMDGhost should pick block 5.
head, err := chainService.lmdGhost(ctx, block1, beaconState, voteTargets)
if err != nil {
@@ -717,7 +805,7 @@ func BenchmarkLMDGhost_8Slots_8Validators(b *testing.B) {
balances[i] = params.BeaconConfig().MaxDepositAmount
}
chainService := setupBeaconChainBenchmark(b, false, beaconDB, true, nil)
chainService := setupBeaconChainBenchmark(b, beaconDB)
// Construct 8 blocks. (Epoch length = 8)
epochLength := uint64(8)
@@ -758,9 +846,19 @@ func BenchmarkLMDGhost_8Slots_8Validators(b *testing.B) {
}
}
voteTargets := make(map[uint64]*pb.BeaconBlock)
blockRoot, err := hashutil.HashBeaconBlock(block)
if err != nil {
b.Fatal(err)
}
voteTargets := make(map[uint64]*pb.AttestationTarget)
target := &pb.AttestationTarget{
Slot: block.Slot,
BlockRoot: blockRoot[:],
ParentRoot: block.ParentRootHash32,
}
for i := 0; i < validatorCount; i++ {
voteTargets[uint64(i)] = block
voteTargets[uint64(i)] = target
}
for i := 0; i < b.N; i++ {
@@ -788,7 +886,7 @@ func BenchmarkLMDGhost_32Slots_8Validators(b *testing.B) {
balances[i] = params.BeaconConfig().MaxDepositAmount
}
chainService := setupBeaconChainBenchmark(b, false, beaconDB, true, nil)
chainService := setupBeaconChainBenchmark(b, beaconDB)
// Construct 8 blocks. (Epoch length = 8)
epochLength := uint64(8)
@@ -829,9 +927,19 @@ func BenchmarkLMDGhost_32Slots_8Validators(b *testing.B) {
}
}
voteTargets := make(map[uint64]*pb.BeaconBlock)
blockRoot, err := hashutil.HashBeaconBlock(block)
if err != nil {
b.Fatal(err)
}
voteTargets := make(map[uint64]*pb.AttestationTarget)
target := &pb.AttestationTarget{
Slot: block.Slot,
BlockRoot: blockRoot[:],
ParentRoot: block.ParentRootHash32,
}
for i := 0; i < validatorCount; i++ {
voteTargets[uint64(i)] = block
voteTargets[uint64(i)] = target
}
for i := 0; i < b.N; i++ {
@@ -857,7 +965,7 @@ func BenchmarkLMDGhost_32Slots_64Validators(b *testing.B) {
balances[i] = params.BeaconConfig().MaxDepositAmount
}
chainService := setupBeaconChainBenchmark(b, false, beaconDB, true, nil)
chainService := setupBeaconChainBenchmark(b, beaconDB)
// Construct 64 blocks. (Epoch length = 64)
epochLength := uint64(32)
@@ -898,9 +1006,19 @@ func BenchmarkLMDGhost_32Slots_64Validators(b *testing.B) {
}
}
voteTargets := make(map[uint64]*pb.BeaconBlock)
blockRoot, err := hashutil.HashBeaconBlock(block)
if err != nil {
b.Fatal(err)
}
voteTargets := make(map[uint64]*pb.AttestationTarget)
target := &pb.AttestationTarget{
Slot: block.Slot,
BlockRoot: blockRoot[:],
ParentRoot: block.ParentRootHash32,
}
for i := 0; i < validatorCount; i++ {
voteTargets[uint64(i)] = block
voteTargets[uint64(i)] = target
}
for i := 0; i < b.N; i++ {
@@ -926,7 +1044,7 @@ func BenchmarkLMDGhost_64Slots_16384Validators(b *testing.B) {
balances[i] = params.BeaconConfig().MaxDepositAmount
}
chainService := setupBeaconChainBenchmark(b, false, beaconDB, true, nil)
chainService := setupBeaconChainBenchmark(b, beaconDB)
// Construct 64 blocks. (Epoch length = 64)
epochLength := uint64(64)
@@ -967,9 +1085,19 @@ func BenchmarkLMDGhost_64Slots_16384Validators(b *testing.B) {
}
}
voteTargets := make(map[uint64]*pb.BeaconBlock)
blockRoot, err := hashutil.HashBeaconBlock(block)
if err != nil {
b.Fatal(err)
}
voteTargets := make(map[uint64]*pb.AttestationTarget)
target := &pb.AttestationTarget{
Slot: block.Slot,
BlockRoot: blockRoot[:],
ParentRoot: block.ParentRootHash32,
}
for i := 0; i < validatorCount; i++ {
voteTargets[uint64(i)] = block
voteTargets[uint64(i)] = target
}
for i := 0; i < b.N; i++ {
@@ -980,32 +1108,19 @@ func BenchmarkLMDGhost_64Slots_16384Validators(b *testing.B) {
}
}
func setupBeaconChainBenchmark(b *testing.B, faultyPoWClient bool, beaconDB *db.BeaconDB, enablePOWChain bool, attsService *attestation.Service) *ChainService {
endpoint := "ws://127.0.0.1"
func setupBeaconChainBenchmark(b *testing.B, beaconDB *db.BeaconDB) *ChainService {
ctx := context.Background()
var web3Service *powchain.Web3Service
var err error
if enablePOWChain {
if faultyPoWClient {
client := &faultyClient{}
web3Service, err = powchain.NewWeb3Service(ctx, &powchain.Web3ServiceConfig{
Endpoint: endpoint,
DepositContract: common.Address{},
Reader: client,
Client: client,
Logger: client,
})
} else {
client := &mockClient{}
web3Service, err = powchain.NewWeb3Service(ctx, &powchain.Web3ServiceConfig{
Endpoint: endpoint,
DepositContract: common.Address{},
Reader: client,
Client: client,
Logger: client,
})
}
}
client := &faultyClient{}
web3Service, err = powchain.NewWeb3Service(ctx, &powchain.Web3ServiceConfig{
Endpoint: endpoint,
DepositContract: common.Address{},
Reader: client,
Client: client,
Logger: client,
})
if err != nil {
b.Fatalf("unable to set up web3 service: %v", err)
}
@@ -1015,7 +1130,7 @@ func setupBeaconChainBenchmark(b *testing.B, faultyPoWClient bool, beaconDB *db.
BeaconDB: beaconDB,
Web3Service: web3Service,
OpsPoolService: &mockOperationService{},
AttsService: attsService,
AttsService: nil,
}
if err != nil {
b.Fatalf("could not register blockchain service: %v", err)
@@ -1325,10 +1440,6 @@ func setupFFGTest(t *testing.T) ([32]byte, *pb.BeaconBlock, *pb.BeaconState, []*
}
func TestVoteCount_CacheEnabledAndMiss(t *testing.T) {
featureconfig.InitFeatureConfig(&featureconfig.FeatureFlagConfig{
EnableBlockAncestorCache: true,
})
beaconDB := internal.SetupDB(t)
defer internal.TeardownDB(t, beaconDB)
genesisBlock := b.NewGenesisBlock([]byte("stateroot"))
@@ -1344,10 +1455,18 @@ func TestVoteCount_CacheEnabledAndMiss(t *testing.T) {
Slot: params.BeaconConfig().GenesisSlot + 5,
ParentRootHash32: genesisRoot[:],
}
pHeadHash, err := hashutil.HashBeaconBlock(potentialHead)
if err != nil {
t.Fatal(err)
}
potentialHead2 := &pb.BeaconBlock{
Slot: params.BeaconConfig().GenesisSlot + 6,
ParentRootHash32: genesisRoot[:],
}
pHeadHash2, err := hashutil.HashBeaconBlock(potentialHead2)
if err != nil {
t.Fatal(err)
}
// We store these potential heads in the DB.
if err := beaconDB.SaveBlock(potentialHead); err != nil {
t.Fatal(err)
@@ -1356,9 +1475,17 @@ func TestVoteCount_CacheEnabledAndMiss(t *testing.T) {
t.Fatal(err)
}
beaconState := &pb.BeaconState{Balances: []uint64{1e9, 1e9}}
voteTargets := make(map[uint64]*pb.BeaconBlock)
voteTargets[0] = potentialHead
voteTargets[1] = potentialHead2
voteTargets := make(map[uint64]*pb.AttestationTarget)
voteTargets[0] = &pb.AttestationTarget{
Slot: potentialHead.Slot,
BlockRoot: pHeadHash[:],
ParentRoot: potentialHead.ParentRootHash32,
}
voteTargets[1] = &pb.AttestationTarget{
Slot: potentialHead2.Slot,
BlockRoot: pHeadHash2[:],
ParentRoot: potentialHead2.ParentRootHash32,
}
count, err := VoteCount(genesisBlock, beaconState, voteTargets, beaconDB)
if err != nil {
t.Fatalf("Could not fetch vote balances: %v", err)
@@ -1374,17 +1501,12 @@ func TestVoteCount_CacheEnabledAndMiss(t *testing.T) {
t.Fatal(err)
}
// Verify the cached block ancestor is genesis block.
h, _ = hashutil.HashBeaconBlock(cachedInfo.Block)
if h != genesisRoot {
if bytesutil.ToBytes32(cachedInfo.Target.BlockRoot) != genesisRoot {
t.Error("could not retrieve the correct ancestor block")
}
}
func TestVoteCount_CacheEnabledAndHit(t *testing.T) {
featureconfig.InitFeatureConfig(&featureconfig.FeatureFlagConfig{
EnableBlockAncestorCache: true,
})
genesisBlock := b.NewGenesisBlock([]byte("stateroot"))
genesisRoot, err := hashutil.HashBeaconBlock(genesisBlock)
if err != nil {
@@ -1403,20 +1525,30 @@ func TestVoteCount_CacheEnabledAndHit(t *testing.T) {
pHeadHash2, _ := hashutil.HashBeaconBlock(potentialHead2)
beaconState := &pb.BeaconState{Balances: []uint64{1e9, 1e9}}
voteTargets := make(map[uint64]*pb.BeaconBlock)
voteTargets[0] = potentialHead
voteTargets[1] = potentialHead2
voteTargets := make(map[uint64]*pb.AttestationTarget)
voteTargets[0] = &pb.AttestationTarget{
Slot: potentialHead.Slot,
BlockRoot: pHeadHash[:],
ParentRoot: potentialHead.ParentRootHash32,
}
voteTargets[1] = &pb.AttestationTarget{
Slot: potentialHead2.Slot,
BlockRoot: pHeadHash2[:],
ParentRoot: potentialHead2.ParentRootHash32,
}
aInfo := &cache.AncestorInfo{
Height: genesisBlock.Slot,
Hash: pHeadHash[:],
Block: genesisBlock,
Target: &pb.AttestationTarget{
Slot: genesisBlock.Slot,
BlockRoot: genesisRoot[:],
ParentRoot: genesisBlock.ParentRootHash32,
},
}
// Presave cached ancestor blocks before running vote count.
if err := blkAncestorCache.AddBlockAncestor(aInfo); err != nil {
t.Fatal(err)
}
aInfo.Hash = pHeadHash2[:]
aInfo.Target.BlockRoot = pHeadHash2[:]
if err := blkAncestorCache.AddBlockAncestor(aInfo); err != nil {
t.Fatal(err)
}

View File

@@ -48,6 +48,7 @@ type ChainService struct {
p2p p2p.Broadcaster
canonicalBlocks map[uint64][]byte
canonicalBlocksLock sync.RWMutex
receiveBlockLock sync.Mutex
}
// Config options for the service.
@@ -147,12 +148,24 @@ func (c *ChainService) initializeBeaconChain(genesisTime time.Time, deposits []*
return nil, fmt.Errorf("could not hash beacon state: %v", err)
}
genBlock := b.NewGenesisBlock(stateRoot[:])
genBlockRoot, err := hashutil.HashBeaconBlock(genBlock)
if err != nil {
return nil, fmt.Errorf("could not hash beacon block: %v", err)
}
// TODO(#2011): Remove this in state caching.
beaconState.LatestBlock = genBlock
if err := c.beaconDB.SaveBlock(genBlock); err != nil {
return nil, fmt.Errorf("could not save genesis block to disk: %v", err)
}
if err := c.beaconDB.SaveAttestationTarget(ctx, &pb.AttestationTarget{
Slot: genBlock.Slot,
BlockRoot: genBlockRoot[:],
ParentRoot: genBlock.ParentRootHash32,
}); err != nil {
return nil, fmt.Errorf("failed to save attestation target: %v", err)
}
if err := c.beaconDB.UpdateChainHead(ctx, genBlock, beaconState); err != nil {
return nil, fmt.Errorf("could not set chain head, %v", err)
}

View File

@@ -206,7 +206,7 @@ func createRandaoReveal(t *testing.T, beaconState *pb.BeaconState, privKeys []*b
return epochSignature.Marshal()
}
func setupGenesisBlock(t *testing.T, cs *ChainService, beaconState *pb.BeaconState) ([32]byte, *pb.BeaconBlock) {
func setupGenesisBlock(t *testing.T, cs *ChainService) ([32]byte, *pb.BeaconBlock) {
genesis := b.NewGenesisBlock([]byte{})
if err := cs.beaconDB.SaveBlock(genesis); err != nil {
t.Fatalf("could not save block to db: %v", err)
@@ -307,7 +307,6 @@ func TestChainStartStop_Initialized(t *testing.T) {
hook := logTest.NewGlobal()
db := internal.SetupDB(t)
defer internal.TeardownDB(t, db)
ctx := context.Background()
chainService := setupBeaconChain(t, db, nil)
@@ -316,11 +315,7 @@ func TestChainStartStop_Initialized(t *testing.T) {
if err := db.InitializeState(context.Background(), unixTime, deposits, &pb.Eth1Data{}); err != nil {
t.Fatalf("Could not initialize beacon state to disk: %v", err)
}
beaconState, err := db.HeadState(ctx)
if err != nil {
t.Fatalf("Could not fetch beacon state: %v", err)
}
setupGenesisBlock(t, chainService, beaconState)
setupGenesisBlock(t, chainService)
// Test the start function.
chainService.Start()

View File

@@ -15,9 +15,10 @@ import (
)
func init() {
featureconfig.InitFeatureConfig(&featureconfig.FeatureFlagConfig{})
featureconfig.InitFeatureConfig(&featureconfig.FeatureFlagConfig{
CacheTreeHash: false,
})
}
func TestGenerateState_OK(t *testing.T) {
b, err := backend.NewSimulatedBackend()
if err != nil {

View File

@@ -32,9 +32,9 @@ var (
// AncestorInfo defines the cached ancestor block object for height.
type AncestorInfo struct {
Hash []byte
Height uint64
Block *pb.BeaconBlock
Hash []byte
Target *pb.AttestationTarget
}
// AncestorBlockCache structs with 1 queue for looking up block ancestor by height.

View File

@@ -14,6 +14,10 @@ func TestHeightHeightFn_OK(t *testing.T) {
aInfo := &AncestorInfo{
Height: height,
Hash: hash,
Target: &pb.AttestationTarget{
Slot: height,
BlockRoot: hash,
},
}
key, err := heightKeyFn(aInfo)
@@ -21,7 +25,7 @@ func TestHeightHeightFn_OK(t *testing.T) {
t.Fatal(err)
}
strHeightKey := string(aInfo.Hash) + strconv.Itoa(int(aInfo.Height))
strHeightKey := string(aInfo.Target.BlockRoot) + strconv.Itoa(int(aInfo.Target.Slot))
if key != strHeightKey {
t.Errorf("Incorrect hash key: %s, expected %s", key, strHeightKey)
}
@@ -42,7 +46,10 @@ func TestAncestorCache_AncestorInfoByHeight(t *testing.T) {
aInfo := &AncestorInfo{
Height: height,
Hash: hash,
Block: &pb.BeaconBlock{Slot: height},
Target: &pb.AttestationTarget{
Slot: height,
BlockRoot: hash,
},
}
fetchedInfo, err := cache.AncestorBySlot(hash, height)
@@ -66,15 +73,15 @@ func TestAncestorCache_AncestorInfoByHeight(t *testing.T) {
if fetchedInfo.Height != height {
t.Errorf(
"Expected fetched slot number to be %d, got %d",
aInfo.Height,
fetchedInfo.Height,
aInfo.Target.Slot,
fetchedInfo.Target.Slot,
)
}
if !reflect.DeepEqual(fetchedInfo.Block, aInfo.Block) {
if !reflect.DeepEqual(fetchedInfo.Target, aInfo.Target) {
t.Errorf(
"Expected fetched info committee to be %v, got %v",
aInfo.Block,
fetchedInfo.Block,
aInfo.Target,
fetchedInfo.Target,
)
}
}
@@ -85,6 +92,9 @@ func TestBlockAncestor_maxSize(t *testing.T) {
for i := 0; i < maxCacheSize+10; i++ {
aInfo := &AncestorInfo{
Height: uint64(i),
Target: &pb.AttestationTarget{
Slot: uint64(i),
},
}
if err := cache.AddBlockAncestor(aInfo); err != nil {
t.Fatal(err)

View File

@@ -6,7 +6,6 @@ go_library(
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/core/balances",
visibility = ["//beacon-chain:__subpackages__"],
deps = [
"//beacon-chain/core/blocks:go_default_library",
"//beacon-chain/core/epoch:go_default_library",
"//beacon-chain/core/helpers:go_default_library",
"//proto/beacon/p2p/v1:go_default_library",

View File

@@ -8,7 +8,6 @@ import (
"errors"
"fmt"
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
"github.com/prysmaticlabs/prysm/beacon-chain/core/epoch"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
@@ -42,7 +41,7 @@ func ExpectedFFGSource(
totalBalance
}
activeValidatorIndices := helpers.ActiveValidatorIndices(state, helpers.CurrentEpoch(state))
didNotAttestIndices := sliceutil.Not(justifiedAttesterIndices, activeValidatorIndices)
didNotAttestIndices := sliceutil.NotUint64(justifiedAttesterIndices, activeValidatorIndices)
for _, index := range didNotAttestIndices {
state.Balances[index] -=
@@ -78,7 +77,7 @@ func ExpectedFFGTarget(
totalBalance
}
activeValidatorIndices := helpers.ActiveValidatorIndices(state, helpers.CurrentEpoch(state))
didNotAttestIndices := sliceutil.Not(boundaryAttesterIndices, activeValidatorIndices)
didNotAttestIndices := sliceutil.NotUint64(boundaryAttesterIndices, activeValidatorIndices)
for _, index := range didNotAttestIndices {
state.Balances[index] -=
@@ -114,7 +113,7 @@ func ExpectedBeaconChainHead(
totalBalance
}
activeValidatorIndices := helpers.ActiveValidatorIndices(state, helpers.CurrentEpoch(state))
didNotAttestIndices := sliceutil.Not(headAttesterIndices, activeValidatorIndices)
didNotAttestIndices := sliceutil.NotUint64(headAttesterIndices, activeValidatorIndices)
for _, index := range didNotAttestIndices {
state.Balances[index] -=
@@ -134,14 +133,15 @@ func ExpectedBeaconChainHead(
func InclusionDistance(
state *pb.BeaconState,
attesterIndices []uint64,
totalBalance uint64) (*pb.BeaconState, error) {
totalBalance uint64,
inclusionDistanceByAttester map[uint64]uint64) (*pb.BeaconState, error) {
baseRewardQuotient := helpers.BaseRewardQuotient(totalBalance)
for _, index := range attesterIndices {
inclusionDistance, err := epoch.InclusionDistance(state, index)
if err != nil {
return nil, fmt.Errorf("could not get inclusion distance: %v", err)
inclusionDistance, ok := inclusionDistanceByAttester[index]
if !ok {
return nil, fmt.Errorf("could not get inclusion distance for attester: %d", index)
}
if inclusionDistance == 0 {
return nil, errors.New("could not process inclusion distance: 0")
@@ -169,7 +169,7 @@ func InactivityFFGSource(
baseRewardQuotient := helpers.BaseRewardQuotient(totalBalance)
activeValidatorIndices := helpers.ActiveValidatorIndices(state, helpers.CurrentEpoch(state))
didNotAttestIndices := sliceutil.Not(justifiedAttesterIndices, activeValidatorIndices)
didNotAttestIndices := sliceutil.NotUint64(justifiedAttesterIndices, activeValidatorIndices)
for _, index := range didNotAttestIndices {
state.Balances[index] -=
@@ -193,7 +193,7 @@ func InactivityFFGTarget(
baseRewardQuotient := helpers.BaseRewardQuotient(totalBalance)
activeValidatorIndices := helpers.ActiveValidatorIndices(state, helpers.CurrentEpoch(state))
didNotAttestIndices := sliceutil.Not(boundaryAttesterIndices, activeValidatorIndices)
didNotAttestIndices := sliceutil.NotUint64(boundaryAttesterIndices, activeValidatorIndices)
for _, index := range didNotAttestIndices {
state.Balances[index] -=
@@ -216,7 +216,7 @@ func InactivityChainHead(
baseRewardQuotient := helpers.BaseRewardQuotient(totalBalance)
activeValidatorIndices := helpers.ActiveValidatorIndices(state, helpers.CurrentEpoch(state))
didNotAttestIndices := sliceutil.Not(headAttesterIndices, activeValidatorIndices)
didNotAttestIndices := sliceutil.NotUint64(headAttesterIndices, activeValidatorIndices)
for _, index := range didNotAttestIndices {
state.Balances[index] -=
@@ -261,14 +261,14 @@ func InactivityExitedPenalties(
func InactivityInclusionDistance(
state *pb.BeaconState,
attesterIndices []uint64,
totalBalance uint64) (*pb.BeaconState, error) {
totalBalance uint64,
inclusionDistanceByAttester map[uint64]uint64) (*pb.BeaconState, error) {
baseRewardQuotient := helpers.BaseRewardQuotient(totalBalance)
for _, index := range attesterIndices {
inclusionDistance, err := epoch.InclusionDistance(state, index)
if err != nil {
return nil, fmt.Errorf("could not get inclusion distance: %v", err)
inclusionDistance, ok := inclusionDistanceByAttester[index]
if !ok {
return nil, fmt.Errorf("could not get inclusion distance for attester: %d", index)
}
baseReward := helpers.BaseReward(state, index, baseRewardQuotient)
state.Balances[index] -= baseReward -
@@ -290,18 +290,19 @@ func InactivityInclusionDistance(
func AttestationInclusion(
state *pb.BeaconState,
totalBalance uint64,
prevEpochAttesterIndices []uint64) (*pb.BeaconState, error) {
prevEpochAttesterIndices []uint64,
inclusionSlotByAttester map[uint64]uint64) (*pb.BeaconState, error) {
baseRewardQuotient := helpers.BaseRewardQuotient(totalBalance)
for _, index := range prevEpochAttesterIndices {
// Get the attestation's inclusion slot using the attestor's index.
slot, err := blocks.AttsInclusionSlot(index)
if err != nil {
return nil, fmt.Errorf("could not get inclusion slot: %v", err)
slot, ok := inclusionSlotByAttester[index]
if !ok {
return nil, fmt.Errorf("could not get inclusion slot for attester: %d", index)
}
proposerIndex, err := helpers.BeaconProposerIndex(state, slot)
if err != nil {
return nil, fmt.Errorf("could not get propoer index: %v", err)
return nil, fmt.Errorf("could not get proposer index: %v", err)
}
state.Balances[proposerIndex] +=
helpers.BaseReward(state, proposerIndex, baseRewardQuotient) /
@@ -365,7 +366,7 @@ func Crosslinks(
}
for _, index := range committee {
baseReward := helpers.BaseReward(state, index, baseRewardQuotient)
if sliceutil.IsIn(index, attestingIndices) {
if sliceutil.IsInUint64(index, attestingIndices) {
state.Balances[index] +=
baseReward * totalAttestingBalance / totalBalance
} else {

View File

@@ -140,10 +140,16 @@ func TestInclusionDistRewards_AccurateRewards(t *testing.T) {
participationBitfield = append(participationBitfield, byte(0xff))
}
attestation := []*pb.PendingAttestation{
{Data: &pb.AttestationData{Slot: params.BeaconConfig().GenesisSlot},
attestations := []*pb.PendingAttestation{
{Data: &pb.AttestationData{
Slot: params.BeaconConfig().GenesisSlot,
JustifiedBlockRootHash32: []byte{},
Shard: 0,
CrosslinkDataRootHash32: params.BeaconConfig().ZeroHash[:],
},
AggregationBitfield: participationBitfield,
InclusionSlot: params.BeaconConfig().GenesisSlot + 5},
InclusionSlot: params.BeaconConfig().GenesisSlot + 5,
},
}
tests := []struct {
@@ -158,15 +164,39 @@ func TestInclusionDistRewards_AccurateRewards(t *testing.T) {
validatorBalances[i] = params.BeaconConfig().MaxDepositAmount
}
state := &pb.BeaconState{
Slot: params.BeaconConfig().GenesisSlot,
ValidatorRegistry: validators,
Balances: validatorBalances,
LatestAttestations: attestation,
Slot: params.BeaconConfig().GenesisSlot + 5,
ValidatorRegistry: validators,
Balances: validatorBalances,
LatestAttestations: attestations,
PreviousJustifiedRoot: []byte{},
LatestCrosslinks: []*pb.Crosslink{
{
CrosslinkDataRootHash32: params.BeaconConfig().ZeroHash[:],
Epoch: params.BeaconConfig().GenesisEpoch,
},
},
}
block := &pb.BeaconBlock{
Body: &pb.BeaconBlockBody{
Attestations: []*pb.Attestation{
{
Data: attestations[0].Data,
},
},
},
}
if _, err := blocks.ProcessBlockAttestations(state, block, false /* verify sig */); err != nil {
t.Fatal(err)
}
inclusionMap := make(map[uint64]uint64)
for _, voted := range tt.voted {
inclusionMap[voted] = state.Slot
}
state, err := InclusionDistance(
state,
tt.voted,
uint64(len(validatorBalances))*params.BeaconConfig().MaxDepositAmount)
uint64(len(validatorBalances))*params.BeaconConfig().MaxDepositAmount,
inclusionMap)
if err != nil {
t.Fatalf("could not execute InclusionDistRewards:%v", err)
}
@@ -206,7 +236,8 @@ func TestInclusionDistRewards_OutOfBounds(t *testing.T) {
ValidatorRegistry: validators,
LatestAttestations: attestation,
}
_, err := InclusionDistance(state, tt.voted, 0)
inclusionMap := make(map[uint64]uint64)
_, err := InclusionDistance(state, tt.voted, 0, inclusionMap)
if err == nil {
t.Fatal("InclusionDistRewards should have failed")
}
@@ -397,10 +428,15 @@ func TestInactivityInclusionPenalty_AccuratePenalties(t *testing.T) {
Balances: validatorBalances,
LatestAttestations: attestation,
}
inclusionMap := make(map[uint64]uint64)
for _, voted := range tt.voted {
inclusionMap[voted] = state.Slot + 1
}
state, err := InactivityInclusionDistance(
state,
tt.voted,
uint64(len(validatorBalances))*params.BeaconConfig().MaxDepositAmount)
uint64(len(validatorBalances))*params.BeaconConfig().MaxDepositAmount,
inclusionMap)
for _, i := range tt.voted {
validatorBalances[i] = 32000055555
@@ -439,7 +475,8 @@ func TestInactivityInclusionPenalty_OutOfBounds(t *testing.T) {
ValidatorRegistry: validators,
LatestAttestations: attestation,
}
_, err := InactivityInclusionDistance(state, tt.voted, 0)
inclusionMap := make(map[uint64]uint64)
_, err := InactivityInclusionDistance(state, tt.voted, 0, inclusionMap)
if err == nil {
t.Fatal("InclusionDistRewards should have failed")
}
@@ -497,10 +534,16 @@ func TestAttestationInclusionRewards_AccurateRewards(t *testing.T) {
if err != nil {
t.Fatal(err)
}
inclusionMap := make(map[uint64]uint64)
for _, voted := range tt.voted {
inclusionMap[voted] = state.Slot
}
state, err = AttestationInclusion(
state,
uint64(len(validatorBalances))*params.BeaconConfig().MaxDepositAmount,
tt.voted)
tt.voted,
inclusionMap)
for _, i := range tt.voted {
validatorBalances[i] = 32000008680
@@ -539,7 +582,8 @@ func TestAttestationInclusionRewards_NoInclusionSlot(t *testing.T) {
ValidatorRegistry: validators,
Balances: validatorBalances,
}
if _, err := AttestationInclusion(state, 0, tt.voted); err == nil {
inclusionMap := make(map[uint64]uint64)
if _, err := AttestationInclusion(state, 0, tt.voted, inclusionMap); err == nil {
t.Fatal("AttestationInclusionRewards should have failed with no inclusion slot")
}
}
@@ -575,7 +619,8 @@ func TestAttestationInclusionRewards_NoProposerIndex(t *testing.T) {
Balances: validatorBalances,
LatestAttestations: attestation,
}
if _, err := AttestationInclusion(state, 0, tt.voted); err == nil {
inclusionMap := make(map[uint64]uint64)
if _, err := AttestationInclusion(state, 0, tt.voted, inclusionMap); err == nil {
t.Fatal("AttestationInclusionRewards should have failed with no proposer index")
}
}

View File

@@ -10,7 +10,6 @@ go_library(
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks",
visibility = ["//beacon-chain:__subpackages__"],
deps = [
"//beacon-chain/cache:go_default_library",
"//beacon-chain/core/helpers:go_default_library",
"//beacon-chain/core/state/stateutils:go_default_library",
"//beacon-chain/core/validators:go_default_library",
@@ -42,6 +41,7 @@ go_test(
"//beacon-chain/core/state:go_default_library",
"//proto/beacon/p2p/v1:go_default_library",
"//shared/bls:go_default_library",
"//shared/featureconfig:go_default_library",
"//shared/forkutil:go_default_library",
"//shared/hashutil:go_default_library",
"//shared/params:go_default_library",

View File

@@ -9,10 +9,8 @@ import (
"errors"
"fmt"
"reflect"
"sync"
"github.com/gogo/protobuf/proto"
"github.com/prysmaticlabs/prysm/beacon-chain/cache"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/beacon-chain/core/state/stateutils"
v "github.com/prysmaticlabs/prysm/beacon-chain/core/validators"
@@ -25,24 +23,6 @@ import (
"github.com/sirupsen/logrus"
)
var committeeCache = cache.NewCommitteesCache()
type attesterInclusionStore struct {
slotLock sync.RWMutex
distLock sync.RWMutex
// attesterInclusion is a mapping that tracks when an attester's attestation
// last get included in beacon chain.
attesterInclusionSlot map[uint64]uint64
// attesterInclusion is a mapping that tracks the difference in slot number
// of when attestation gets submitted and when it gets included.
attesterInclusionDist map[uint64]uint64
}
var attsInclStore = attesterInclusionStore{
attesterInclusionSlot: make(map[uint64]uint64),
attesterInclusionDist: make(map[uint64]uint64),
}
// VerifyProposerSignature uses BLS signature verification to ensure
// the correct proposer created an incoming beacon block during state
// transition processing.
@@ -437,38 +417,6 @@ func ProcessBlockAttestations(
return nil, fmt.Errorf("could not verify attestation at index %d in block: %v", idx, err)
}
var IndicesInCommittee []uint64
// get the validator indices from the attestation using committees info cache.
cachedCommittees, err := committeeCache.CommitteesInfoBySlot(attestation.Data.Slot)
if err != nil {
return nil, err
}
if cachedCommittees == nil {
crosslinkCommittees, err := helpers.CrosslinkCommitteesAtSlot(beaconState, attestation.Data.Slot, false /* registryChange */)
if err != nil {
return nil, err
}
cachedCommittees = helpers.ToCommitteeCache(attestation.Data.Slot, crosslinkCommittees)
if err := committeeCache.AddCommittees(cachedCommittees); err != nil {
return nil, err
}
}
for _, v := range cachedCommittees.Committees {
if v.Shard == attestation.Data.Shard {
IndicesInCommittee = v.Committee
break
}
}
attsInclStore.slotLock.Lock()
attsInclStore.distLock.Lock()
defer attsInclStore.slotLock.Unlock()
defer attsInclStore.distLock.Unlock()
for _, index := range IndicesInCommittee {
attsInclStore.attesterInclusionSlot[index] = beaconState.Slot
attsInclStore.attesterInclusionDist[index] = beaconState.Slot - attestation.Data.Slot
}
beaconState.LatestAttestations = append(beaconState.LatestAttestations, &pb.PendingAttestation{
Data: attestation.Data,
AggregationBitfield: attestation.AggregationBitfield,
@@ -759,25 +707,3 @@ func verifyExit(beaconState *pb.BeaconState, exit *pb.VoluntaryExit, verifySigna
}
return nil
}
// AttsInclusionSlot returns the slot of when an attestator's attestation last gets included
// in the beacon chain by a proposer.
func AttsInclusionSlot(index uint64) (uint64, error) {
attsInclStore.slotLock.RLock()
attsInclStore.slotLock.RUnlock()
if slot, ok := attsInclStore.attesterInclusionSlot[index]; ok {
return slot, nil
}
return 0, fmt.Errorf("no inclusion slot for attestor %d", index)
}
// AttsInclusionDistance returns diff in slot of when an attestator's attestation gets submitted
// and included.
func AttsInclusionDistance(index uint64) (uint64, error) {
attsInclStore.distLock.RLock()
attsInclStore.distLock.RUnlock()
if slot, ok := attsInclStore.attesterInclusionDist[index]; ok {
return slot, nil
}
return 0, fmt.Errorf("no inclusion distance for attestor %d", index)
}

View File

@@ -15,12 +15,19 @@ import (
"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared/bls"
"github.com/prysmaticlabs/prysm/shared/featureconfig"
"github.com/prysmaticlabs/prysm/shared/forkutil"
"github.com/prysmaticlabs/prysm/shared/params"
"github.com/prysmaticlabs/prysm/shared/ssz"
"github.com/prysmaticlabs/prysm/shared/trieutil"
)
func init() {
featureconfig.InitFeatureConfig(&featureconfig.FeatureFlagConfig{
CacheTreeHash: false,
})
}
func setupInitialDeposits(t *testing.T, numDeposits int) ([]*pb.Deposit, []*bls.SecretKey) {
privKeys := make([]*bls.SecretKey, numDeposits)
deposits := make([]*pb.Deposit, numDeposits)

View File

@@ -65,29 +65,6 @@ func InclusionSlot(state *pb.BeaconState, validatorIndex uint64) (uint64, error)
return lowestSlotIncluded, nil
}
// InclusionDistance returns the difference in slot number of when attestation
// gets submitted and when it gets included.
//
// Spec pseudocode definition:
// Let inclusion_distance(state, index) =
// a.slot_included - a.data.slot where a is the above attestation same as
// inclusion_slot.
func InclusionDistance(state *pb.BeaconState, validatorIndex uint64) (uint64, error) {
for _, attestation := range state.LatestAttestations {
participatedValidators, err := helpers.AttestationParticipants(state, attestation.Data, attestation.AggregationBitfield)
if err != nil {
return 0, fmt.Errorf("could not get attestation participants: %v", err)
}
for _, index := range participatedValidators {
if index == validatorIndex {
return attestation.InclusionSlot - attestation.Data.Slot, nil
}
}
}
return 0, fmt.Errorf("could not find inclusion distance for validator index %d", validatorIndex)
}
// AttestingValidators returns the validators of the winning root.
//
// Spec pseudocode definition:

View File

@@ -254,53 +254,3 @@ func TestInclusionSlot_SlotNotFound(t *testing.T) {
t.Errorf("Expected %s, received %v", want, err)
}
}
func TestInclusionDistance_CorrectDistance(t *testing.T) {
state := buildState(params.BeaconConfig().GenesisSlot, params.BeaconConfig().DepositsForChainStart)
var participationBitfield []byte
for i := 0; i < 16; i++ {
participationBitfield = append(participationBitfield, byte(0xff))
}
state.LatestAttestations = []*pb.PendingAttestation{
{Data: &pb.AttestationData{Slot: params.BeaconConfig().GenesisSlot},
AggregationBitfield: participationBitfield,
InclusionSlot: params.BeaconConfig().GenesisSlot + 100},
}
distance, err := InclusionDistance(state, 251)
if err != nil {
t.Fatalf("Could not execute InclusionDistance: %v", err)
}
// Inclusion distance is 100 because input validator index is 45,
// validator 45's attested slot 0 and got included slot 100.
if distance != 100 {
t.Errorf("Incorrect distance. Wanted: %d, got: %d",
100, distance)
}
}
func TestInclusionDistance_InvalidBitfield(t *testing.T) {
state := buildState(params.BeaconConfig().GenesisSlot, params.BeaconConfig().DepositsForChainStart)
state.LatestAttestations = []*pb.PendingAttestation{
{Data: &pb.AttestationData{Slot: params.BeaconConfig().GenesisSlot},
AggregationBitfield: []byte{},
InclusionSlot: 100},
}
want := fmt.Sprintf("wanted participants bitfield length %d, got: %d", 16, 0)
if _, err := InclusionDistance(state, 0); !strings.Contains(err.Error(), want) {
t.Errorf("Expected %s, received %v", want, err)
}
}
func TestInclusionDistance_NotFound(t *testing.T) {
state := buildState(0, params.BeaconConfig().SlotsPerEpoch)
badIndex := uint64(10000)
want := fmt.Sprintf("could not find inclusion distance for validator index %d", badIndex)
if _, err := InclusionDistance(state, badIndex); !strings.Contains(err.Error(), want) {
t.Errorf("Expected %s, received %v", want, err)
}
}

View File

@@ -45,6 +45,7 @@ go_test(
deps = [
"//beacon-chain/cache:go_default_library",
"//proto/beacon/p2p/v1:go_default_library",
"//shared/featureconfig:go_default_library",
"//shared/params:go_default_library",
"@com_github_gogo_protobuf//proto:go_default_library",
"@org_golang_google_grpc//codes:go_default_library",

View File

@@ -363,7 +363,7 @@ func VerifyBitfield(bitfield []byte, committeeSize int) (bool, error) {
// * ``assignment[0]`` is the list of validators in the committee
// * ``assignment[1]`` is the shard to which the committee is assigned
// * ``assignment[2]`` is the slot at which the committee is assigned
// * ``assignment[3]`` is a bool signalling if the validator is expected to propose
// * ``assignment[3]`` is a bool signaling if the validator is expected to propose
// a beacon block at the assigned slot.
// """
// previous_epoch = get_previous_epoch(state)

View File

@@ -6,9 +6,16 @@ import (
"github.com/gogo/protobuf/proto"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared/featureconfig"
"github.com/prysmaticlabs/prysm/shared/params"
)
func init() {
featureconfig.InitFeatureConfig(&featureconfig.FeatureFlagConfig{
CacheTreeHash: false,
})
}
func TestEncodeDecodeDepositInput_Ok(t *testing.T) {
input := &pb.DepositInput{
Pubkey: []byte("key"),

View File

@@ -8,14 +8,20 @@ import (
"testing"
"time"
"github.com/prysmaticlabs/prysm/shared/hashutil"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared/featureconfig"
"github.com/prysmaticlabs/prysm/shared/hashutil"
"github.com/prysmaticlabs/prysm/shared/params"
)
func init() {
featureconfig.InitFeatureConfig(&featureconfig.FeatureFlagConfig{
CacheTreeHash: false,
})
}
func TestGenesisBeaconState_OK(t *testing.T) {
if params.BeaconConfig().SlotsPerEpoch != 64 {
t.Errorf("SlotsPerEpoch should be 64 for these tests to pass")

View File

@@ -223,6 +223,9 @@ func ProcessEpoch(ctx context.Context, state *pb.BeaconState, block *pb.BeaconBl
prevEpochHeadAttestations := []*pb.PendingAttestation{}
prevEpochHeadAttesterIndices := []uint64{}
inclusionSlotByAttester := make(map[uint64]uint64)
inclusionDistanceByAttester := make(map[uint64]uint64)
for _, attestation := range state.LatestAttestations {
// We determine the attestation participants.
@@ -234,6 +237,11 @@ func ProcessEpoch(ctx context.Context, state *pb.BeaconState, block *pb.BeaconBl
return nil, err
}
for _, participant := range attesterIndices {
inclusionDistanceByAttester[participant] = state.Slot - attestation.Data.Slot
inclusionSlotByAttester[participant] = attestation.InclusionSlot
}
// We extract the attestations from the current epoch.
if currentEpoch == helpers.SlotToEpoch(attestation.Data.Slot) {
currentEpochAttestations = append(currentEpochAttestations, attestation)
@@ -248,14 +256,14 @@ func ProcessEpoch(ctx context.Context, state *pb.BeaconState, block *pb.BeaconBl
sameRoot := bytes.Equal(attestationData.EpochBoundaryRootHash32, boundaryBlockRoot)
if sameRoot {
currentEpochBoundaryAttestations = append(currentEpochBoundaryAttestations, attestation)
currentBoundaryAttesterIndices = sliceutil.Union(currentBoundaryAttesterIndices, attesterIndices)
currentBoundaryAttesterIndices = sliceutil.UnionUint64(currentBoundaryAttesterIndices, attesterIndices)
}
}
// We extract the attestations from the previous epoch.
if prevEpoch == helpers.SlotToEpoch(attestation.Data.Slot) {
prevEpochAttestations = append(prevEpochAttestations, attestation)
prevEpochAttesterIndices = sliceutil.Union(prevEpochAttesterIndices, attesterIndices)
prevEpochAttesterIndices = sliceutil.UnionUint64(prevEpochAttesterIndices, attesterIndices)
// We extract the previous epoch boundary attestations.
prevBoundaryBlockRoot, err := b.BlockRoot(state,
@@ -265,7 +273,7 @@ func ProcessEpoch(ctx context.Context, state *pb.BeaconState, block *pb.BeaconBl
}
if bytes.Equal(attestation.Data.EpochBoundaryRootHash32, prevBoundaryBlockRoot) {
prevEpochBoundaryAttestations = append(prevEpochBoundaryAttestations, attestation)
prevEpochBoundaryAttesterIndices = sliceutil.Union(prevEpochBoundaryAttesterIndices, attesterIndices)
prevEpochBoundaryAttesterIndices = sliceutil.UnionUint64(prevEpochBoundaryAttesterIndices, attesterIndices)
}
// We extract the previous epoch head attestations.
@@ -277,7 +285,7 @@ func ProcessEpoch(ctx context.Context, state *pb.BeaconState, block *pb.BeaconBl
attestationData := attestation.Data
if bytes.Equal(attestationData.BeaconBlockRootHash32, canonicalBlockRoot) {
prevEpochHeadAttestations = append(prevEpochHeadAttestations, attestation)
prevEpochHeadAttesterIndices = sliceutil.Union(prevEpochHeadAttesterIndices, attesterIndices)
prevEpochHeadAttesterIndices = sliceutil.UnionUint64(prevEpochHeadAttesterIndices, attesterIndices)
}
}
}
@@ -358,7 +366,8 @@ func ProcessEpoch(ctx context.Context, state *pb.BeaconState, block *pb.BeaconBl
state, err = bal.InclusionDistance(
state,
prevEpochAttesterIndices,
totalBalance)
totalBalance,
inclusionDistanceByAttester)
if err != nil {
return nil, fmt.Errorf("could not calculate inclusion dist rewards: %v", err)
}
@@ -367,7 +376,9 @@ func ProcessEpoch(ctx context.Context, state *pb.BeaconState, block *pb.BeaconBl
}
case epochsSinceFinality > 4:
log.WithField("epochSinceFinality", epochsSinceFinality).Info("Applying quadratic leak penalties")
if config.Logging {
log.WithField("epochSinceFinality", epochsSinceFinality).Info("Applying quadratic leak penalties")
}
// Apply penalties for long inactive FFG source participants.
state = bal.InactivityFFGSource(
state,
@@ -397,7 +408,8 @@ func ProcessEpoch(ctx context.Context, state *pb.BeaconState, block *pb.BeaconBl
state, err = bal.InactivityInclusionDistance(
state,
prevEpochAttesterIndices,
totalBalance)
totalBalance,
inclusionDistanceByAttester)
if err != nil {
return nil, fmt.Errorf("could not calculate inclusion penalties: %v", err)
}
@@ -407,7 +419,8 @@ func ProcessEpoch(ctx context.Context, state *pb.BeaconState, block *pb.BeaconBl
state, err = bal.AttestationInclusion(
state,
totalBalance,
prevEpochAttesterIndices)
prevEpochAttesterIndices,
inclusionSlotByAttester)
if err != nil {
return nil, fmt.Errorf("could not process attestation inclusion rewards: %v", err)
}

View File

@@ -54,7 +54,7 @@ func ValidatorIndices(
return nil, err
}
attesterIndicesIntersection = sliceutil.Union(attesterIndicesIntersection, attesterIndices)
attesterIndicesIntersection = sliceutil.UnionUint64(attesterIndicesIntersection, attesterIndices)
}
return attesterIndicesIntersection, nil
@@ -87,7 +87,7 @@ func AttestingValidatorIndices(
if err != nil {
return nil, fmt.Errorf("could not get attester indices: %v", err)
}
validatorIndicesCommittees = sliceutil.Union(validatorIndicesCommittees, validatorIndicesCommittee)
validatorIndicesCommittees = sliceutil.UnionUint64(validatorIndicesCommittees, validatorIndicesCommittee)
}
}
return validatorIndicesCommittees, nil

View File

@@ -16,16 +16,33 @@ func (db *BeaconDB) SaveAttestation(ctx context.Context, attestation *pb.Attesta
ctx, span := trace.StartSpan(ctx, "beaconDB.SaveAttestation")
defer span.End()
encodedState, err := proto.Marshal(attestation)
encodedAtt, err := proto.Marshal(attestation)
if err != nil {
return err
}
hash := hashutil.Hash(encodedState)
hash := hashutil.Hash(encodedAtt)
return db.update(func(tx *bolt.Tx) error {
a := tx.Bucket(attestationBucket)
return a.Put(hash[:], encodedState)
return a.Put(hash[:], encodedAtt)
})
}
// SaveAttestationTarget puts the attestation target record into the beacon chain db.
func (db *BeaconDB) SaveAttestationTarget(ctx context.Context, attTarget *pb.AttestationTarget) error {
ctx, span := trace.StartSpan(ctx, "beaconDB.SaveAttestationTarget")
defer span.End()
encodedAttTgt, err := proto.Marshal(attTarget)
if err != nil {
return err
}
return db.update(func(tx *bolt.Tx) error {
a := tx.Bucket(attestationTargetBucket)
return a.Put(attTarget.BlockRoot, encodedAttTgt)
})
}
@@ -85,6 +102,25 @@ func (db *BeaconDB) Attestations() ([]*pb.Attestation, error) {
return attestations, err
}
// AttestationTarget retrieves an attestation target record from the db using its hash.
func (db *BeaconDB) AttestationTarget(hash [32]byte) (*pb.AttestationTarget, error) {
var attTgt *pb.AttestationTarget
err := db.view(func(tx *bolt.Tx) error {
a := tx.Bucket(attestationTargetBucket)
enc := a.Get(hash[:])
if enc == nil {
return nil
}
var err error
attTgt, err = createAttestationTarget(enc)
return err
})
return attTgt, err
}
// HasAttestation checks if the attestation exists.
func (db *BeaconDB) HasAttestation(hash [32]byte) bool {
exists := false
@@ -105,3 +141,11 @@ func createAttestation(enc []byte) (*pb.Attestation, error) {
}
return protoAttestation, nil
}
func createAttestationTarget(enc []byte) (*pb.AttestationTarget, error) {
protoAttTgt := &pb.AttestationTarget{}
if err := proto.Unmarshal(enc, protoAttTgt); err != nil {
return nil, fmt.Errorf("failed to unmarshal encoding: %v", err)
}
return protoAttTgt, nil
}

View File

@@ -8,10 +8,17 @@ import (
"github.com/gogo/protobuf/proto"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared/featureconfig"
"github.com/prysmaticlabs/prysm/shared/hashutil"
"github.com/prysmaticlabs/prysm/shared/params"
)
func init() {
featureconfig.InitFeatureConfig(&featureconfig.FeatureFlagConfig{
CacheTreeHash: false,
})
}
func TestNilDB_OK(t *testing.T) {
db := setupDB(t)
defer teardownDB(t, db)

View File

@@ -20,11 +20,14 @@ var log = logrus.WithField("prefix", "beacondb")
// For example, instead of defining get, put, remove
// This defines methods such as getBlock, saveBlocksAndAttestations, etc.
type BeaconDB struct {
stateLock sync.RWMutex
currentState *pb.BeaconState
stateHash [32]byte
db *bolt.DB
DatabasePath string
// state objects and caches
stateLock sync.RWMutex
serializedState []byte
stateHash [32]byte
validatorRegistry []*pb.Validator
validatorBalances []uint64
db *bolt.DB
DatabasePath string
// Beacon block info in memory.
highestBlockSlot uint64
@@ -82,8 +85,8 @@ func NewDB(dirPath string) (*BeaconDB, error) {
db := &BeaconDB{db: boltDB, DatabasePath: dirPath}
if err := db.update(func(tx *bolt.Tx) error {
return createBuckets(tx, blockBucket, attestationBucket, mainChainBucket, histStateBucket,
chainInfoBucket, cleanupHistoryBucket, blockOperationsBucket, validatorBucket)
return createBuckets(tx, blockBucket, attestationBucket, attestationTargetBucket, mainChainBucket,
histStateBucket, chainInfoBucket, cleanupHistoryBucket, blockOperationsBucket, validatorBucket)
}); err != nil {
return nil, err
}

View File

@@ -15,13 +15,14 @@ import (
// The fields below define the suffix of keys in the db.
var (
attestationBucket = []byte("attestation-bucket")
blockOperationsBucket = []byte("block-operations-bucket")
blockBucket = []byte("block-bucket")
mainChainBucket = []byte("main-chain-bucket")
histStateBucket = []byte("historical-state-bucket")
chainInfoBucket = []byte("chain-info")
validatorBucket = []byte("validator")
attestationBucket = []byte("attestation-bucket")
attestationTargetBucket = []byte("attestation-target-bucket")
blockOperationsBucket = []byte("block-operations-bucket")
blockBucket = []byte("block-bucket")
mainChainBucket = []byte("main-chain-bucket")
histStateBucket = []byte("historical-state-bucket")
chainInfoBucket = []byte("chain-info")
validatorBucket = []byte("validator")
mainChainHeightKey = []byte("chain-height")
stateLookupKey = []byte("state")

View File

@@ -46,7 +46,7 @@ func (db *BeaconDB) InitializeState(ctx context.Context, genesisTime uint64, dep
blockEnc, _ := proto.Marshal(genesisBlock)
zeroBinary := encodeSlotNumber(0)
db.currentState = beaconState
db.serializedState = stateEnc
db.stateHash = stateHash
if err := db.SaveState(ctx, beaconState); err != nil {
@@ -100,11 +100,15 @@ func (db *BeaconDB) HeadState(ctx context.Context) (*pb.BeaconState, error) {
lockSpan.End()
// Return in-memory cached state, if available.
if db.currentState != nil {
_, span := trace.StartSpan(ctx, "proto.Clone")
if db.serializedState != nil {
_, span := trace.StartSpan(ctx, "proto.Marshal")
defer span.End()
cachedState := proto.Clone(db.currentState).(*pb.BeaconState)
return cachedState, nil
newState := &pb.BeaconState{}
// For each READ we unmarshal the serialized state into a new state struct and return that.
if err := proto.Unmarshal(db.serializedState, newState); err != nil {
return nil, err
}
return newState, nil
}
var beaconState *pb.BeaconState
@@ -117,9 +121,13 @@ func (db *BeaconDB) HeadState(ctx context.Context) (*pb.BeaconState, error) {
var err error
beaconState, err = createState(enc)
if beaconState != nil && beaconState.Slot > db.highestBlockSlot {
db.highestBlockSlot = beaconState.Slot
}
db.serializedState = enc
db.stateHash = hashutil.Hash(enc)
return err
})
@@ -141,21 +149,19 @@ func (db *BeaconDB) SaveState(ctx context.Context, beaconState *pb.BeaconState)
defer db.stateLock.Unlock()
lockSpan.End()
// Clone to prevent mutations of the cached copy
ctx, cloneSpan := trace.StartSpan(ctx, "proto.Clone")
currentState, ok := proto.Clone(beaconState).(*pb.BeaconState)
if !ok {
cloneSpan.End()
return errors.New("could not clone beacon state")
}
db.currentState = currentState
cloneSpan.End()
stateHash, err := hashutil.HashProto(beaconState)
// For each WRITE of the state, we serialize the inputted state and save it in memory,
// and then the state is saved to disk.
enc, err := proto.Marshal(beaconState)
if err != nil {
return err
}
stateHash := hashutil.Hash(enc)
tempState := &pb.BeaconState{}
tempState.ValidatorRegistry = beaconState.ValidatorRegistry
copy(db.validatorBalances, beaconState.Balances)
db.validatorRegistry = proto.Clone(tempState).(*pb.BeaconState).ValidatorRegistry
db.serializedState = enc
db.stateHash = stateHash
if err := db.SaveHistoricalState(ctx, beaconState); err != nil {
@@ -165,16 +171,9 @@ func (db *BeaconDB) SaveState(ctx context.Context, beaconState *pb.BeaconState)
return db.update(func(tx *bolt.Tx) error {
chainInfo := tx.Bucket(chainInfoBucket)
_, marshalSpan := trace.StartSpan(ctx, "proto.Marshal")
beaconStateEnc, err := proto.Marshal(beaconState)
if err != nil {
return err
}
marshalSpan.End()
stateBytes.Set(float64(len(beaconStateEnc)))
stateBytes.Set(float64(len(enc)))
reportStateMetrics(beaconState)
return chainInfo.Put(stateLookupKey, beaconStateEnc)
return chainInfo.Put(stateLookupKey, enc)
})
}
@@ -330,14 +329,14 @@ func (db *BeaconDB) ValidatorRegistry(ctx context.Context) ([]*pb.Validator, err
defer db.stateLock.RUnlock()
// Return in-memory cached state, if available.
if db.currentState != nil {
if db.validatorRegistry != nil {
_, span := trace.StartSpan(ctx, "proto.Clone.ValidatorRegistry")
defer span.End()
newRegistry := make([]*pb.Validator, len(db.currentState.ValidatorRegistry))
for i, v := range db.currentState.ValidatorRegistry {
newRegistry[i] = proto.Clone(v).(*pb.Validator)
tempState := &pb.BeaconState{
ValidatorRegistry: db.validatorRegistry,
}
return newRegistry, nil
newState := proto.Clone(tempState).(*pb.BeaconState)
return newState.ValidatorRegistry, nil
}
var beaconState *pb.BeaconState
@@ -359,20 +358,61 @@ func (db *BeaconDB) ValidatorRegistry(ctx context.Context) ([]*pb.Validator, err
return beaconState.ValidatorRegistry, err
}
// ValidatorFromState fetches the validator with the desired index from the cached registry.
func (db *BeaconDB) ValidatorFromState(ctx context.Context, index uint64) (*pb.Validator, error) {
ctx, span := trace.StartSpan(ctx, "BeaconDB.ValidatorFromState")
defer span.End()
db.stateLock.RLock()
defer db.stateLock.RUnlock()
if db.validatorRegistry != nil {
// return error if it's an invalid validator index.
if index >= uint64(len(db.validatorRegistry)) {
return nil, fmt.Errorf("invalid validator index %d", index)
}
validator := proto.Clone(db.validatorRegistry[index]).(*pb.Validator)
return validator, nil
}
var beaconState *pb.BeaconState
err := db.view(func(tx *bolt.Tx) error {
chainInfo := tx.Bucket(chainInfoBucket)
enc := chainInfo.Get(stateLookupKey)
if enc == nil {
return nil
}
var err error
beaconState, err = createState(enc)
if beaconState != nil && beaconState.Slot > db.highestBlockSlot {
db.highestBlockSlot = beaconState.Slot
}
return err
})
// return error if it's an invalid validator index.
if index >= uint64(len(db.validatorRegistry)) {
return nil, fmt.Errorf("invalid validator index %d", index)
}
return beaconState.ValidatorRegistry[index], err
}
// ValidatorBalances fetches the current validator balances stored in state.
func (db *BeaconDB) ValidatorBalances(ctx context.Context) ([]uint64, error) {
ctx, span := trace.StartSpan(ctx, "BeaconDB.ValidatorRegistry")
ctx, span := trace.StartSpan(ctx, "BeaconDB.ValidatorBalances")
defer span.End()
db.stateLock.RLock()
defer db.stateLock.RUnlock()
// Return in-memory cached state, if available.
if db.currentState != nil {
_, span := trace.StartSpan(ctx, "proto.Clone.ValidatorRegistry")
if db.validatorBalances != nil {
_, span := trace.StartSpan(ctx, "BeaconDB.Copy.Balances")
defer span.End()
newBalances := make([]uint64, len(db.currentState.Balances))
copy(newBalances, db.currentState.Balances)
newBalances := make([]uint64, len(db.validatorBalances))
copy(newBalances, db.validatorBalances)
return newBalances, nil
}

View File

@@ -93,7 +93,7 @@ func TestFinalizeState_OK(t *testing.T) {
defer teardownDB(t, db)
genesisTime := uint64(time.Now().Unix())
deposits, _ := setupInitialDeposits(t, 10)
deposits, _ := setupInitialDeposits(t, 20)
if err := db.InitializeState(context.Background(), genesisTime, deposits, &pb.Eth1Data{}); err != nil {
t.Fatalf("Failed to initialize state: %v", err)
}
@@ -138,7 +138,10 @@ func BenchmarkState_ReadingFromCache(b *testing.B) {
b.Fatalf("Could not save beacon state to cache from DB: %v", err)
}
if db.currentState.Slot != params.BeaconConfig().GenesisSlot+1 {
savedState := &pb.BeaconState{}
savedState.Unmarshal(db.serializedState)
if savedState.Slot != params.BeaconConfig().GenesisSlot+1 {
b.Fatal("cache should be prepared on state after saving to DB")
}

View File

@@ -2,6 +2,7 @@ package db
import (
"bytes"
"context"
"encoding/binary"
"fmt"
@@ -37,13 +38,28 @@ func (db *BeaconDB) SaveValidatorIndexBatch(pubKey []byte, index int) error {
}
// ValidatorIndex accepts a public key and returns the corresponding validator index.
// If the validator index is not found in DB, as a fail over, it searches the state and
// saves it to the DB when found.
func (db *BeaconDB) ValidatorIndex(pubKey []byte) (uint64, error) {
if !db.HasValidator(pubKey) {
state, err := db.HeadState(context.Background())
if err != nil {
return 0, err
}
for i := 0; i < len(state.ValidatorRegistry); i++ {
v := state.ValidatorRegistry[i]
if bytes.Equal(v.Pubkey, pubKey) {
if err := db.SaveValidatorIndex(pubKey, i); err != nil {
return 0, err
}
return uint64(i), nil
}
}
return 0, fmt.Errorf("validator %#x does not exist", pubKey)
}
var index uint64
h := hashutil.Hash(pubKey)
err := db.view(func(tx *bolt.Tx) error {
bucket := tx.Bucket(validatorBucket)

View File

@@ -1,11 +1,13 @@
package db
import (
"context"
"fmt"
"strings"
"testing"
"github.com/boltdb/bolt"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared/hashutil"
)
@@ -47,11 +49,14 @@ func TestSaveAndDeleteValidatorIndex_OK(t *testing.T) {
p1 := []byte{'1', '2', '3'}
if err := db.SaveValidatorIndex(p1, 3); err != nil {
t.Fatalf("Failed to save vallidator index: %v", err)
t.Fatalf("Failed to save validator index: %v", err)
}
if err := db.SaveState(context.Background(), &pb.BeaconState{}); err != nil {
t.Fatalf("Failed to save state: %v", err)
}
index, err := db.ValidatorIndex(p1)
if err != nil {
t.Fatalf("Failed to call Attestation: %v", err)
t.Fatalf("Failed to call validator Index: %v", err)
}
if index != 3 {
t.Fatalf("Saved index and retrieved index are not equal: %#x and %#x", 3, index)

View File

@@ -29,7 +29,7 @@ func (db *BeaconDB) VerifyContractAddress(ctx context.Context, addr common.Addre
}
if !bytes.Equal(expectedAddress, addr.Bytes()) {
return fmt.Errorf("invalid deposit contract address, expected %#x", expectedAddress)
return fmt.Errorf("invalid deposit contract address, expected %#x - try running with --clear-db", expectedAddress)
}
return nil

View File

@@ -63,7 +63,7 @@ func main() {
cmd.TraceSampleFractionFlag,
cmd.MonitoringPortFlag,
cmd.DisableMonitoringFlag,
cmd.ClearDBFlag,
cmd.ClearDB,
debug.PProfFlag,
debug.PProfAddrFlag,
debug.PProfPortFlag,

View File

@@ -4,6 +4,8 @@ package node
import (
"context"
"fmt"
"io/ioutil"
"net/http"
"os"
"os/signal"
"path"
@@ -168,7 +170,7 @@ func (b *BeaconNode) Close() {
func (b *BeaconNode) startDB(ctx *cli.Context) error {
baseDir := ctx.GlobalString(cmd.DataDirFlag.Name)
dbPath := path.Join(baseDir, beaconChainDBName)
if b.ctx.GlobalBool(cmd.ClearDBFlag.Name) {
if b.ctx.GlobalBool(cmd.ClearDB.Name) {
if err := db.ClearDB(dbPath); err != nil {
return err
}
@@ -246,7 +248,22 @@ func (b *BeaconNode) registerPOWChainService(cliCtx *cli.Context) error {
depAddress := cliCtx.GlobalString(utils.DepositContractFlag.Name)
if depAddress == "" {
log.Fatal("No deposit contract specified. Add --deposit-contract with a valid deposit contract address to start.")
log.Infof("Fetching testnet cluster address from %s...", params.BeaconConfig().TestnetContractEndpoint)
resp, err := http.Get(params.BeaconConfig().TestnetContractEndpoint)
if err != nil {
log.Fatalf("Could not get latest deposit contract address: %v", err)
}
defer func() {
if err := resp.Body.Close(); err != nil {
log.Fatal(err)
}
}()
contractResponse, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
depAddress = string(contractResponse)
}
if !common.IsHexAddress(depAddress) {
@@ -344,6 +361,11 @@ func (b *BeaconNode) registerRPCService(ctx *cli.Context) error {
return err
}
var syncService *rbcsync.Service
if err := b.services.FetchService(&syncService); err != nil {
return err
}
port := ctx.GlobalString(utils.RPCPort.Name)
cert := ctx.GlobalString(utils.CertFlag.Name)
key := ctx.GlobalString(utils.KeyFlag.Name)
@@ -355,6 +377,7 @@ func (b *BeaconNode) registerRPCService(ctx *cli.Context) error {
ChainService: chainService,
OperationService: operationService,
POWChainService: web3Service,
SyncService: syncService,
})
return b.services.RegisterService(rpcService)

View File

@@ -28,6 +28,7 @@ var topicMappings = map[pb.Topic]proto.Message{
func configureP2P(ctx *cli.Context) (*p2p.Server, error) {
s, err := p2p.NewServer(&p2p.ServerConfig{
NoDiscovery: ctx.GlobalBool(cmd.NoDiscovery.Name),
BootstrapNodeAddr: ctx.GlobalString(cmd.BootstrapNode.Name),
RelayNodeAddr: ctx.GlobalString(cmd.RelayNode.Name),
Port: ctx.GlobalInt(cmd.P2PPort.Name),

View File

@@ -72,11 +72,11 @@ func TestRoutineContextClosing_Ok(t *testing.T) {
s := NewOpsPoolService(context.Background(), &Config{BeaconDB: db})
exitRoutine := make(chan bool)
go func(tt *testing.T) {
go func() {
s.removeOperations()
s.saveOperations()
<-exitRoutine
}(t)
}()
s.cancel()
exitRoutine <- true
testutil.AssertLogsContain(t, hook, "operations service context closed, exiting remove goroutine")

View File

@@ -46,6 +46,7 @@ go_test(
"//contracts/deposit-contract:go_default_library",
"//proto/beacon/p2p/v1:go_default_library",
"//shared/event:go_default_library",
"//shared/featureconfig:go_default_library",
"//shared/ssz:go_default_library",
"//shared/testutil:go_default_library",
"@com_github_ethereum_go_ethereum//:go_default_library",

View File

@@ -13,8 +13,9 @@ import (
gethTypes "github.com/ethereum/go-ethereum/core/types"
)
var endpoint = "ws://127.0.0.1"
func TestLatestMainchainInfo_OK(t *testing.T) {
endpoint := "ws://127.0.0.1"
testAcc, err := setup()
if err != nil {
t.Fatalf("Unable to set up simulated backend %v", err)
@@ -84,7 +85,6 @@ func TestLatestMainchainInfo_OK(t *testing.T) {
}
func TestBlockHashByHeight_ReturnsHash(t *testing.T) {
endpoint := "ws://127.0.0.1"
web3Service, err := NewWeb3Service(context.Background(), &Web3ServiceConfig{
Endpoint: endpoint,
BlockFetcher: &goodFetcher{},
@@ -123,7 +123,6 @@ func TestBlockHashByHeight_ReturnsHash(t *testing.T) {
}
func TestBlockExists_ValidHash(t *testing.T) {
endpoint := "ws://127.0.0.1"
web3Service, err := NewWeb3Service(context.Background(), &Web3ServiceConfig{
Endpoint: endpoint,
BlockFetcher: &goodFetcher{},
@@ -163,7 +162,6 @@ func TestBlockExists_ValidHash(t *testing.T) {
}
func TestBlockExists_InvalidHash(t *testing.T) {
endpoint := "ws://127.0.0.1"
web3Service, err := NewWeb3Service(context.Background(), &Web3ServiceConfig{
Endpoint: endpoint,
BlockFetcher: &goodFetcher{},
@@ -179,7 +177,6 @@ func TestBlockExists_InvalidHash(t *testing.T) {
}
func TestBlockExists_UsesCachedBlockInfo(t *testing.T) {
endpoint := "ws://127.0.0.1"
web3Service, err := NewWeb3Service(context.Background(), &Web3ServiceConfig{
Endpoint: endpoint,
BlockFetcher: nil, // nil blockFetcher would panic if cached value not used

View File

@@ -189,7 +189,7 @@ func (w *Web3Service) processPastLogs() error {
// last polled to now.
func (w *Web3Service) requestBatchedLogs() error {
// We request for the nth block behind the current head, in order to have
// stabilised logs when we retrieve it from the 1.0 chain.
// stabilized logs when we retrieve it from the 1.0 chain.
requestedBlock := big.NewInt(0).Sub(w.blockHeight, big.NewInt(params.BeaconConfig().LogBlockDelay))
query := ethereum.FilterQuery{
Addresses: []common.Address{

View File

@@ -14,14 +14,20 @@ import (
"github.com/prysmaticlabs/prysm/beacon-chain/db"
contracts "github.com/prysmaticlabs/prysm/contracts/deposit-contract"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared/featureconfig"
"github.com/prysmaticlabs/prysm/shared/ssz"
"github.com/prysmaticlabs/prysm/shared/testutil"
logTest "github.com/sirupsen/logrus/hooks/test"
)
func init() {
featureconfig.InitFeatureConfig(&featureconfig.FeatureFlagConfig{
CacheTreeHash: false,
})
}
func TestProcessDepositLog_OK(t *testing.T) {
hook := logTest.NewGlobal()
endpoint := "ws://127.0.0.1"
testAcc, err := setup()
if err != nil {
t.Fatalf("Unable to set up simulated backend %v", err)
@@ -84,7 +90,6 @@ func TestProcessDepositLog_OK(t *testing.T) {
}
func TestProcessDepositLog_InsertsPendingDeposit(t *testing.T) {
endpoint := "ws://127.0.0.1"
testAcc, err := setup()
if err != nil {
t.Fatalf("Unable to set up simulated backend %v", err)
@@ -146,7 +151,6 @@ func TestProcessDepositLog_InsertsPendingDeposit(t *testing.T) {
}
func TestUnpackDepositLogData_OK(t *testing.T) {
endpoint := "ws://127.0.0.1"
testAcc, err := setup()
if err != nil {
t.Fatalf("Unable to set up simulated backend %v", err)
@@ -230,7 +234,6 @@ func TestUnpackDepositLogData_OK(t *testing.T) {
func TestProcessChainStartLog_8DuplicatePubkeys(t *testing.T) {
hook := logTest.NewGlobal()
endpoint := "ws://127.0.0.1"
testAcc, err := setup()
if err != nil {
t.Fatalf("Unable to set up simulated backend %v", err)
@@ -316,7 +319,6 @@ func TestProcessChainStartLog_8DuplicatePubkeys(t *testing.T) {
func TestProcessChainStartLog_8UniquePubkeys(t *testing.T) {
hook := logTest.NewGlobal()
endpoint := "ws://127.0.0.1"
testAcc, err := setup()
if err != nil {
t.Fatalf("Unable to set up simulated backend %v", err)
@@ -401,7 +403,6 @@ func TestProcessChainStartLog_8UniquePubkeys(t *testing.T) {
}
func TestUnpackChainStartLogData_OK(t *testing.T) {
endpoint := "ws://127.0.0.1"
testAcc, err := setup()
if err != nil {
t.Fatalf("Unable to set up simulated backend %v", err)
@@ -470,7 +471,6 @@ func TestUnpackChainStartLogData_OK(t *testing.T) {
}
func TestHasChainStartLogOccurred_OK(t *testing.T) {
endpoint := "ws://127.0.0.1"
testAcc, err := setup()
if err != nil {
t.Fatalf("Unable to set up simulated backend %v", err)
@@ -531,7 +531,6 @@ func TestHasChainStartLogOccurred_OK(t *testing.T) {
}
func TestETH1DataGenesis_OK(t *testing.T) {
endpoint := "ws://127.0.0.1"
testAcc, err := setup()
if err != nil {
t.Fatalf("Unable to set up simulated backend %v", err)

View File

@@ -38,16 +38,6 @@ func (g *goodReader) SubscribeNewHead(ctx context.Context, ch chan<- *gethTypes.
return new(event.Feed).Subscribe(ch), nil
}
type badLogger struct{}
func (b *badLogger) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]gethTypes.Log, error) {
return nil, errors.New("unable to retrieve logs")
}
func (b *badLogger) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuery, ch chan<- gethTypes.Log) (ethereum.Subscription, error) {
return nil, errors.New("subscription has failed")
}
type goodLogger struct{}
func (g *goodLogger) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuery, ch chan<- gethTypes.Log) (ethereum.Subscription, error) {
@@ -198,7 +188,6 @@ func TestNewWeb3Service_OK(t *testing.T) {
func TestStart_OK(t *testing.T) {
hook := logTest.NewGlobal()
endpoint := "ws://127.0.0.1"
testAcc, err := setup()
if err != nil {
t.Fatalf("Unable to set up simulated backend %v", err)
@@ -237,7 +226,6 @@ func TestStart_OK(t *testing.T) {
func TestStop_OK(t *testing.T) {
hook := logTest.NewGlobal()
endpoint := "ws://127.0.0.1"
testAcc, err := setup()
if err != nil {
t.Fatalf("Unable to set up simulated backend %v", err)
@@ -274,7 +262,7 @@ func TestStop_OK(t *testing.T) {
}
func TestInitDataFromContract_OK(t *testing.T) {
endpoint := "ws://127.0.0.1"
testAcc, err := setup()
if err != nil {
t.Fatalf("Unable to set up simulated backend %v", err)
@@ -304,7 +292,7 @@ func TestInitDataFromContract_OK(t *testing.T) {
func TestWeb3Service_BadReader(t *testing.T) {
hook := logTest.NewGlobal()
endpoint := "ws://127.0.0.1"
testAcc, err := setup()
if err != nil {
t.Fatalf("Unable to set up simulated backend %v", err)
@@ -367,7 +355,7 @@ func TestStatus(t *testing.T) {
func TestHandlePanic_OK(t *testing.T) {
hook := logTest.NewGlobal()
endpoint := "ws://127.0.0.1"
web3Service, err := NewWeb3Service(context.Background(), &Web3ServiceConfig{
Endpoint: endpoint,
BlockFetcher: nil, // nil blockFetcher would panic if cached value not used

View File

@@ -24,6 +24,8 @@ import (
logTest "github.com/sirupsen/logrus/hooks/test"
)
var closedContext = "context closed"
type faultyPOWChainService struct {
chainStartFeed *event.Feed
hashesByHeight map[int][]byte
@@ -129,8 +131,7 @@ func TestWaitForChainStart_ContextClosed(t *testing.T) {
defer ctrl.Finish()
mockStream := internal.NewMockBeaconService_WaitForChainStartServer(ctrl)
go func(tt *testing.T) {
want := "context closed"
if err := beaconServer.WaitForChainStart(&ptypes.Empty{}, mockStream); !strings.Contains(err.Error(), want) {
if err := beaconServer.WaitForChainStart(&ptypes.Empty{}, mockStream); !strings.Contains(err.Error(), closedContext) {
tt.Errorf("Could not call RPC method: %v", err)
}
<-exitRoutine

View File

@@ -55,6 +55,10 @@ type powChainService interface {
ChainStartDeposits() [][]byte
}
type syncService interface {
Status() error
}
// Service defining an RPC server for a beacon node.
type Service struct {
ctx context.Context
@@ -63,6 +67,7 @@ type Service struct {
chainService chainService
powChainService powChainService
operationService operationService
syncService syncService
port string
listener net.Listener
withCert string
@@ -82,6 +87,7 @@ type Config struct {
ChainService chainService
POWChainService powChainService
OperationService operationService
SyncService syncService
}
// NewRPCService creates a new instance of a struct implementing the BeaconServiceServer
@@ -95,6 +101,7 @@ func NewRPCService(ctx context.Context, cfg *Config) *Service {
chainService: cfg.ChainService,
powChainService: cfg.POWChainService,
operationService: cfg.OperationService,
syncService: cfg.SyncService,
port: cfg.Port,
withCert: cfg.CertFlag,
withKey: cfg.KeyFlag,
@@ -174,6 +181,9 @@ func (s *Service) Start() {
reflection.Register(s.grpcServer)
go func() {
for s.syncService.Status() != nil {
time.Sleep(time.Second * params.BeaconConfig().RPCSyncCheck)
}
if s.listener != nil {
if err := s.grpcServer.Serve(s.listener); err != nil {
log.Errorf("Could not serve gRPC: %v", err)

View File

@@ -121,12 +121,20 @@ func newMockChainService() *mockChainService {
}
}
type mockSyncService struct {
}
func (ms *mockSyncService) Status() error {
return nil
}
func TestLifecycle_OK(t *testing.T) {
hook := logTest.NewGlobal()
rpcService := NewRPCService(context.Background(), &Config{
Port: "7348",
CertFlag: "alice.crt",
KeyFlag: "alice.key",
Port: "7348",
CertFlag: "alice.crt",
KeyFlag: "alice.key",
SyncService: &mockSyncService{},
})
rpcService.Start()
@@ -150,7 +158,8 @@ func TestRPC_BadEndpoint(t *testing.T) {
hook := logTest.NewLocal(fl.Logger)
rpcService := NewRPCService(context.Background(), &Config{
Port: "ralph merkle!!!",
Port: "ralph merkle!!!",
SyncService: &mockSyncService{},
})
if val, ok := log.(*TestLogger).testMap["error"]; ok {
@@ -179,7 +188,8 @@ func TestStatus_CredentialError(t *testing.T) {
func TestRPC_InsecureEndpoint(t *testing.T) {
hook := logTest.NewGlobal()
rpcService := NewRPCService(context.Background(), &Config{
Port: "7777",
Port: "7777",
SyncService: &mockSyncService{},
})
rpcService.Start()

View File

@@ -110,7 +110,7 @@ func (vs *ValidatorServer) ValidatorPerformance(
// 1.) The list of validators in the committee.
// 2.) The shard to which the committee is assigned.
// 3.) The slot at which the committee is assigned.
// 4.) The bool signalling if the validator is expected to propose a block at the assigned slot.
// 4.) The bool signaling if the validator is expected to propose a block at the assigned slot.
func (vs *ValidatorServer) CommitteeAssignment(
ctx context.Context,
req *pb.CommitteeAssignmentsRequest) (*pb.CommitteeAssignmentResponse, error) {

View File

@@ -64,6 +64,48 @@ func TestValidatorIndex_OK(t *testing.T) {
}
}
func TestValidatorIndex_InStateNotInDB(t *testing.T) {
db := internal.SetupDB(t)
defer internal.TeardownDB(t, db)
pubKey := []byte{'A'}
// Wanted validator with public key 'A' is in index '1'.
s := &pbp2p.BeaconState{
ValidatorRegistry: []*pbp2p.Validator{{Pubkey: []byte{0}}, {Pubkey: []byte{'A'}}, {Pubkey: []byte{'B'}}},
}
if err := db.SaveState(context.Background(), s); err != nil {
t.Fatal(err)
}
validatorServer := &ValidatorServer{
beaconDB: db,
}
req := &pb.ValidatorIndexRequest{
PublicKey: pubKey,
}
// Verify index can be retrieved from state when it's not saved in DB.
res, err := validatorServer.ValidatorIndex(context.Background(), req)
if err != nil {
t.Fatal(err)
}
if res.Index != 1 {
t.Errorf("Wanted index 1 got %d", res.Index)
}
// Verify index is also saved in DB.
idx, err := validatorServer.beaconDB.ValidatorIndex(pubKey)
if err != nil {
t.Fatal(err)
}
if idx != 1 {
t.Errorf("Wanted index 1 in DB got %d", res.Index)
}
}
func TestNextEpochCommitteeAssignment_WrongPubkeyLength(t *testing.T) {
db := internal.SetupDB(t)
ctx := context.Background()
@@ -691,7 +733,9 @@ func TestAddNonActivePublicKeysAssignmentStatus(t *testing.T) {
},
},
}
if err := db.SaveState(context.Background(), beaconState); err != nil {
t.Fatal(err)
}
vs := &ValidatorServer{
beaconDB: db,
}

View File

@@ -15,6 +15,8 @@ import (
"go.opencensus.io/trace"
)
const noMsgData = "message contains no data"
func (s *InitialSync) checkBlockValidity(ctx context.Context, block *pb.BeaconBlock) error {
ctx, span := trace.StartSpan(ctx, "beacon-chain.sync.initial-sync.checkBlockValidity")
defer span.End()
@@ -41,7 +43,7 @@ func (s *InitialSync) doesParentExist(block *pb.BeaconBlock) bool {
func safelyHandleMessage(fn func(p2p.Message), msg p2p.Message) {
defer func() {
if r := recover(); r != nil {
printedMsg := "message contains no data"
printedMsg := noMsgData
if msg.Data != nil {
printedMsg = proto.MarshalTextString(msg.Data)
}

View File

@@ -17,6 +17,8 @@ import (
"sync"
"time"
"github.com/prysmaticlabs/prysm/shared/hashutil"
"github.com/ethereum/go-ethereum/common"
"github.com/gogo/protobuf/proto"
"github.com/prysmaticlabs/prysm/beacon-chain/blockchain"
@@ -203,6 +205,17 @@ func (s *InitialSync) exitInitialSync(ctx context.Context, block *pb.BeaconBlock
if err := s.db.SaveBlock(block); err != nil {
return err
}
root, err := hashutil.HashBeaconBlock(block)
if err != nil {
return fmt.Errorf("failed to tree hash block: %v", err)
}
if err := s.db.SaveAttestationTarget(ctx, &pb.AttestationTarget{
Slot: block.Slot,
BlockRoot: root[:],
ParentRoot: block.ParentRootHash32,
}); err != nil {
return fmt.Errorf("failed to save attestation target: %v", err)
}
state, err = s.chainService.ApplyBlockStateTransition(ctx, block, state)
if err != nil {
switch err.(type) {

View File

@@ -165,6 +165,13 @@ func (s *InitialSync) validateAndSaveNextBlock(ctx context.Context, block *pb.Be
if err := s.db.SaveBlock(block); err != nil {
return err
}
if err := s.db.SaveAttestationTarget(ctx, &pb.AttestationTarget{
Slot: block.Slot,
BlockRoot: root[:],
ParentRoot: block.ParentRootHash32,
}); err != nil {
return fmt.Errorf("could not to save attestation target: %v", err)
}
state, err = s.chainService.ApplyBlockStateTransition(ctx, block, state)
if err != nil {
return fmt.Errorf("could not apply block state transition: %v", err)

View File

@@ -3,6 +3,8 @@ package initialsync
import (
"context"
"github.com/prysmaticlabs/prysm/shared/hashutil"
"github.com/prysmaticlabs/prysm/beacon-chain/core/validators"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared/bytesutil"
@@ -38,6 +40,20 @@ func (s *InitialSync) processState(msg p2p.Message) {
return
}
root, err := hashutil.HashBeaconBlock(finalizedState.LatestBlock)
if err != nil {
log.Errorf("Could not hash finalized block %v", err)
return
}
if err := s.db.SaveAttestationTarget(ctx, &pb.AttestationTarget{
Slot: finalizedState.LatestBlock.Slot,
BlockRoot: root[:],
ParentRoot: finalizedState.LatestBlock.ParentRootHash32,
}); err != nil {
log.Errorf("Could not to save attestation target: %v", err)
return
}
if err := s.db.SaveJustifiedState(finalizedState); err != nil {
log.Errorf("Could not set beacon state for initial sync %v", err)
return

View File

@@ -24,6 +24,10 @@ var (
Name: "regsync_received_blocks",
Help: "The number of received blocks",
})
forkedBlock = promauto.NewCounter(prometheus.CounterOpts{
Name: "regsync_received_forked_blocks",
Help: "The number of received forked blocks",
})
recBlockAnnounce = promauto.NewCounter(prometheus.CounterOpts{
Name: "regsync_received_block_announce",
Help: "The number of received block announcements",

View File

@@ -191,6 +191,9 @@ func (rs *RegularSync) validateAndProcessBlock(
span.AddAttributes(trace.BoolAttribute("invalidBlock", true))
return nil, nil, false, err
}
} else {
forkedBlock.Inc()
log.Warnf("Received Block from a Forked Chain with root %#x and slot %d", blockRoot, block.Slot)
}
sentBlocks.Inc()

View File

@@ -433,20 +433,16 @@ func (rs *RegularSync) receiveAttestation(msg p2p.Message) error {
}
// Skip if attestation slot is older than last finalized slot in state.
beaconState, err := rs.db.HeadState(ctx)
if err != nil {
log.Errorf("Failed to get beacon state: %v", err)
return err
}
highestSlot := rs.db.HighestBlockSlot()
span.AddAttributes(
trace.Int64Attribute("attestation.Data.Slot", int64(attestation.Data.Slot)),
trace.Int64Attribute("finalized state slot", int64(beaconState.Slot-params.BeaconConfig().SlotsPerEpoch)),
trace.Int64Attribute("finalized state slot", int64(highestSlot-params.BeaconConfig().SlotsPerEpoch)),
)
if attestation.Data.Slot < beaconState.Slot-params.BeaconConfig().SlotsPerEpoch {
if attestation.Data.Slot < highestSlot-params.BeaconConfig().SlotsPerEpoch {
log.WithFields(logrus.Fields{
"receivedSlot": attestation.Data.Slot,
"epochSlot": beaconState.Slot - params.BeaconConfig().SlotsPerEpoch},
"epochSlot": highestSlot - params.BeaconConfig().SlotsPerEpoch},
).Debug("Skipping received attestation with slot smaller than one epoch ago")
return nil
}

View File

@@ -14,6 +14,7 @@ import (
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared/bytesutil"
"github.com/prysmaticlabs/prysm/shared/event"
"github.com/prysmaticlabs/prysm/shared/featureconfig"
"github.com/prysmaticlabs/prysm/shared/hashutil"
"github.com/prysmaticlabs/prysm/shared/p2p"
"github.com/prysmaticlabs/prysm/shared/params"
@@ -25,6 +26,9 @@ import (
func init() {
logrus.SetLevel(logrus.DebugLevel)
logrus.SetOutput(ioutil.Discard)
featureconfig.InitFeatureConfig(&featureconfig.FeatureFlagConfig{
CacheTreeHash: false,
})
}
type mockP2P struct {
@@ -116,7 +120,7 @@ func (ma *mockAttestationService) IncomingAttestationFeed() *event.Feed {
return new(event.Feed)
}
func setupService(t *testing.T, db *db.BeaconDB) *RegularSync {
func setupService(db *db.BeaconDB) *RegularSync {
cfg := &RegularSyncConfig{
BlockAnnounceBufferSize: 0,
BlockBufferSize: 0,
@@ -174,7 +178,7 @@ func TestProcessBlock_OK(t *testing.T) {
}
}
genesisTime := uint64(time.Now().Unix())
deposits, _ := setupInitialDeposits(t, 10)
deposits, _ := setupInitialDeposits(t)
if err := db.InitializeState(context.Background(), genesisTime, deposits, &pb.Eth1Data{}); err != nil {
t.Fatalf("Failed to initialize state: %v", err)
}
@@ -249,7 +253,7 @@ func TestProcessBlock_MultipleBlocksProcessedOK(t *testing.T) {
}
}
genesisTime := uint64(time.Now().Unix())
deposits, _ := setupInitialDeposits(t, 10)
deposits, _ := setupInitialDeposits(t)
if err := db.InitializeState(context.Background(), genesisTime, deposits, &pb.Eth1Data{}); err != nil {
t.Fatal(err)
}
@@ -343,7 +347,7 @@ func TestBlockRequest_InvalidMsg(t *testing.T) {
db := internal.SetupDB(t)
defer internal.TeardownDB(t, db)
ss := setupService(t, db)
ss := setupService(db)
malformedRequest := &pb.BeaconBlockAnnounce{
Hash: []byte{'t', 'e', 's', 't'},
@@ -366,7 +370,7 @@ func TestBlockRequest_OK(t *testing.T) {
db := internal.SetupDB(t)
defer internal.TeardownDB(t, db)
ss := setupService(t, db)
ss := setupService(db)
request1 := &pb.BeaconBlockRequestBySlotNumber{
SlotNumber: 20,
@@ -396,11 +400,21 @@ func TestReceiveAttestation_OK(t *testing.T) {
db := internal.SetupDB(t)
defer internal.TeardownDB(t, db)
if err := db.SaveState(ctx, &pb.BeaconState{
beaconState := &pb.BeaconState{
Slot: params.BeaconConfig().GenesisSlot + 2,
}); err != nil {
}
if err := db.SaveState(ctx, beaconState); err != nil {
t.Fatalf("Could not save state: %v", err)
}
beaconBlock := &pb.BeaconBlock{
Slot: beaconState.Slot,
}
if err := db.SaveBlock(beaconBlock); err != nil {
t.Fatal(err)
}
if err := db.UpdateChainHead(ctx, beaconBlock, beaconState); err != nil {
t.Fatal(err)
}
cfg := &RegularSyncConfig{
ChainService: ms,
AttsService: &mockAttestationService{},
@@ -656,10 +670,10 @@ func TestHandleStateReq_NOState(t *testing.T) {
db := internal.SetupDB(t)
defer internal.TeardownDB(t, db)
ss := setupService(t, db)
ss := setupService(db)
genesisTime := uint64(time.Now().Unix())
deposits, _ := setupInitialDeposits(t, 10)
deposits, _ := setupInitialDeposits(t)
if err := db.InitializeState(context.Background(), genesisTime, deposits, &pb.Eth1Data{}); err != nil {
t.Fatalf("Failed to initialize state: %v", err)
}
@@ -708,7 +722,7 @@ func TestHandleStateReq_OK(t *testing.T) {
t.Fatalf("could not hash beacon state: %v", err)
}
ss := setupService(t, db)
ss := setupService(db)
request1 := &pb.BeaconStateRequest{
FinalizedStateRootHash32S: stateRoot[:],

View File

@@ -2,6 +2,7 @@ package sync
import (
"context"
"errors"
"fmt"
"github.com/prysmaticlabs/prysm/beacon-chain/db"
@@ -16,9 +17,10 @@ var slog = logrus.WithField("prefix", "sync")
// Service defines the main routines used in the sync service.
type Service struct {
RegularSync *RegularSync
InitialSync *initialsync.InitialSync
Querier *Querier
RegularSync *RegularSync
InitialSync *initialsync.InitialSync
Querier *Querier
querierFinished bool
}
// Config defines the configured services required for sync to work.
@@ -60,9 +62,10 @@ func NewSyncService(ctx context.Context, cfg *Config) *Service {
is := initialsync.NewInitialSyncService(ctx, isCfg)
return &Service{
RegularSync: rs,
InitialSync: is,
Querier: sq,
RegularSync: rs,
InitialSync: is,
Querier: sq,
querierFinished: false,
}
}
@@ -91,9 +94,14 @@ func (ss *Service) Stop() error {
// Status checks the status of the node. It returns nil if it's synced
// with the rest of the network and no errors occurred. Otherwise, it returns an error.
func (ss *Service) Status() error {
if !ss.querierFinished {
return errors.New("querier is still running")
}
if !ss.Querier.chainStarted {
return nil
}
if ss.Querier.atGenesis {
return nil
}
@@ -102,6 +110,9 @@ func (ss *Service) Status() error {
if err != nil {
return fmt.Errorf("could not retrieve chain head %v", err)
}
if blk == nil {
return errors.New("no chain head exists in db")
}
if blk.Slot < ss.InitialSync.HighestObservedSlot() {
return fmt.Errorf("node is not synced as the current chain head is at slot %d", blk.Slot-params.BeaconConfig().GenesisSlot)
}
@@ -114,6 +125,7 @@ func (ss *Service) run() {
if err != nil {
slog.Fatalf("Unable to retrieve result from sync querier %v", err)
}
ss.querierFinished = true
// Sets the highest observed slot from querier.
ss.InitialSync.InitializeObservedSlot(ss.Querier.currentHeadSlot)

View File

@@ -45,9 +45,10 @@ func initializeTestSyncService(ctx context.Context, cfg *Config, synced bool) *S
return services
}
func setupInitialDeposits(t *testing.T, numDeposits int) ([]*pb.Deposit, []*bls.SecretKey) {
privKeys := make([]*bls.SecretKey, numDeposits)
deposits := make([]*pb.Deposit, numDeposits)
func setupInitialDeposits(t *testing.T) ([]*pb.Deposit, []*bls.SecretKey) {
numOfDeposits := 10
privKeys := make([]*bls.SecretKey, numOfDeposits)
deposits := make([]*pb.Deposit, numOfDeposits)
for i := 0; i < len(deposits); i++ {
priv, err := bls.RandKey(rand.Reader)
if err != nil {
@@ -71,7 +72,7 @@ func setupTestSyncService(t *testing.T, synced bool) (*Service, *db.BeaconDB) {
db := internal.SetupDB(t)
unixTime := uint64(time.Now().Unix())
deposits, _ := setupInitialDeposits(t, 10)
deposits, _ := setupInitialDeposits(t)
if err := db.InitializeState(context.Background(), unixTime, deposits, &pb.Eth1Data{}); err != nil {
t.Fatalf("Failed to initialize state: %v", err)
}

View File

@@ -44,6 +44,7 @@ var appHelpFlagGroups = []flagGroup{
{
Name: "cmd",
Flags: []cli.Flag{
cmd.NoDiscovery,
cmd.BootstrapNode,
cmd.RelayNode,
cmd.P2PPort,

View File

@@ -44,6 +44,7 @@ spec:
image: gcr.io/prysmaticlabs/prysm/beacon-chain:latest
args:
- --web3provider=wss://goerli.infura.io/ws/v3/be3fb7ed377c418087602876a40affa1
- --http-web3provider=https://goerli.infura.io/v3/be3fb7ed377c418087602876a40affa1
#- --verbosity=debug
- --deposit-contract=$(DEPOSIT_CONTRACT_ADDRESS)
- --rpc-port=4000

View File

@@ -72,3 +72,9 @@ spec:
port:
number: 8080
host: contract-address-http.beacon-chain.svc.cluster.local
corsPolicy:
allowOrigin:
- '*'
allowMethods:
- GET
maxAge: '24h'

View File

@@ -48,7 +48,7 @@ func (x Validator_StatusFlags) String() string {
}
func (Validator_StatusFlags) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_e719e7d82cfa7b0d, []int{7, 0}
return fileDescriptor_e719e7d82cfa7b0d, []int{8, 0}
}
type BeaconState struct {
@@ -803,6 +803,69 @@ func (m *AttestationData) GetCrosslinkDataRootHash32() []byte {
return nil
}
type AttestationTarget struct {
Slot uint64 `protobuf:"varint,1,opt,name=slot,proto3" json:"slot,omitempty"`
BlockRoot []byte `protobuf:"bytes,2,opt,name=block_root,json=blockRoot,proto3" json:"block_root,omitempty"`
ParentRoot []byte `protobuf:"bytes,3,opt,name=parent_root,json=parentRoot,proto3" json:"parent_root,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *AttestationTarget) Reset() { *m = AttestationTarget{} }
func (m *AttestationTarget) String() string { return proto.CompactTextString(m) }
func (*AttestationTarget) ProtoMessage() {}
func (*AttestationTarget) Descriptor() ([]byte, []int) {
return fileDescriptor_e719e7d82cfa7b0d, []int{5}
}
func (m *AttestationTarget) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *AttestationTarget) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_AttestationTarget.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalTo(b)
if err != nil {
return nil, err
}
return b[:n], nil
}
}
func (m *AttestationTarget) XXX_Merge(src proto.Message) {
xxx_messageInfo_AttestationTarget.Merge(m, src)
}
func (m *AttestationTarget) XXX_Size() int {
return m.Size()
}
func (m *AttestationTarget) XXX_DiscardUnknown() {
xxx_messageInfo_AttestationTarget.DiscardUnknown(m)
}
var xxx_messageInfo_AttestationTarget proto.InternalMessageInfo
func (m *AttestationTarget) GetSlot() uint64 {
if m != nil {
return m.Slot
}
return 0
}
func (m *AttestationTarget) GetBlockRoot() []byte {
if m != nil {
return m.BlockRoot
}
return nil
}
func (m *AttestationTarget) GetParentRoot() []byte {
if m != nil {
return m.ParentRoot
}
return nil
}
type AttestationDataAndCustodyBit struct {
Data *AttestationData `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
CustodyBit bool `protobuf:"varint,2,opt,name=custody_bit,json=custodyBit,proto3" json:"custody_bit,omitempty"`
@@ -815,7 +878,7 @@ func (m *AttestationDataAndCustodyBit) Reset() { *m = AttestationDataAnd
func (m *AttestationDataAndCustodyBit) String() string { return proto.CompactTextString(m) }
func (*AttestationDataAndCustodyBit) ProtoMessage() {}
func (*AttestationDataAndCustodyBit) Descriptor() ([]byte, []int) {
return fileDescriptor_e719e7d82cfa7b0d, []int{5}
return fileDescriptor_e719e7d82cfa7b0d, []int{6}
}
func (m *AttestationDataAndCustodyBit) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -872,7 +935,7 @@ func (m *IndexedAttestation) Reset() { *m = IndexedAttestation{} }
func (m *IndexedAttestation) String() string { return proto.CompactTextString(m) }
func (*IndexedAttestation) ProtoMessage() {}
func (*IndexedAttestation) Descriptor() ([]byte, []int) {
return fileDescriptor_e719e7d82cfa7b0d, []int{6}
return fileDescriptor_e719e7d82cfa7b0d, []int{7}
}
func (m *IndexedAttestation) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -951,7 +1014,7 @@ func (m *Validator) Reset() { *m = Validator{} }
func (m *Validator) String() string { return proto.CompactTextString(m) }
func (*Validator) ProtoMessage() {}
func (*Validator) Descriptor() ([]byte, []int) {
return fileDescriptor_e719e7d82cfa7b0d, []int{7}
return fileDescriptor_e719e7d82cfa7b0d, []int{8}
}
func (m *Validator) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1081,7 +1144,7 @@ func (m *ShardReassignmentRecord) Reset() { *m = ShardReassignmentRecord
func (m *ShardReassignmentRecord) String() string { return proto.CompactTextString(m) }
func (*ShardReassignmentRecord) ProtoMessage() {}
func (*ShardReassignmentRecord) Descriptor() ([]byte, []int) {
return fileDescriptor_e719e7d82cfa7b0d, []int{8}
return fileDescriptor_e719e7d82cfa7b0d, []int{9}
}
func (m *ShardReassignmentRecord) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1144,7 +1207,7 @@ func (m *Crosslink) Reset() { *m = Crosslink{} }
func (m *Crosslink) String() string { return proto.CompactTextString(m) }
func (*Crosslink) ProtoMessage() {}
func (*Crosslink) Descriptor() ([]byte, []int) {
return fileDescriptor_e719e7d82cfa7b0d, []int{9}
return fileDescriptor_e719e7d82cfa7b0d, []int{10}
}
func (m *Crosslink) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1213,7 +1276,7 @@ func (m *BeaconBlock) Reset() { *m = BeaconBlock{} }
func (m *BeaconBlock) String() string { return proto.CompactTextString(m) }
func (*BeaconBlock) ProtoMessage() {}
func (*BeaconBlock) Descriptor() ([]byte, []int) {
return fileDescriptor_e719e7d82cfa7b0d, []int{10}
return fileDescriptor_e719e7d82cfa7b0d, []int{11}
}
func (m *BeaconBlock) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1323,7 +1386,7 @@ func (m *BeaconBlockBody) Reset() { *m = BeaconBlockBody{} }
func (m *BeaconBlockBody) String() string { return proto.CompactTextString(m) }
func (*BeaconBlockBody) ProtoMessage() {}
func (*BeaconBlockBody) Descriptor() ([]byte, []int) {
return fileDescriptor_e719e7d82cfa7b0d, []int{11}
return fileDescriptor_e719e7d82cfa7b0d, []int{12}
}
func (m *BeaconBlockBody) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1421,7 +1484,7 @@ func (m *DepositInput) Reset() { *m = DepositInput{} }
func (m *DepositInput) String() string { return proto.CompactTextString(m) }
func (*DepositInput) ProtoMessage() {}
func (*DepositInput) Descriptor() ([]byte, []int) {
return fileDescriptor_e719e7d82cfa7b0d, []int{12}
return fileDescriptor_e719e7d82cfa7b0d, []int{13}
}
func (m *DepositInput) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1484,7 +1547,7 @@ func (m *ProposalSignedData) Reset() { *m = ProposalSignedData{} }
func (m *ProposalSignedData) String() string { return proto.CompactTextString(m) }
func (*ProposalSignedData) ProtoMessage() {}
func (*ProposalSignedData) Descriptor() ([]byte, []int) {
return fileDescriptor_e719e7d82cfa7b0d, []int{13}
return fileDescriptor_e719e7d82cfa7b0d, []int{14}
}
func (m *ProposalSignedData) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1548,7 +1611,7 @@ func (m *SlashableAttestation) Reset() { *m = SlashableAttestation{} }
func (m *SlashableAttestation) String() string { return proto.CompactTextString(m) }
func (*SlashableAttestation) ProtoMessage() {}
func (*SlashableAttestation) Descriptor() ([]byte, []int) {
return fileDescriptor_e719e7d82cfa7b0d, []int{14}
return fileDescriptor_e719e7d82cfa7b0d, []int{15}
}
func (m *SlashableAttestation) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1621,7 +1684,7 @@ func (m *DepositData) Reset() { *m = DepositData{} }
func (m *DepositData) String() string { return proto.CompactTextString(m) }
func (*DepositData) ProtoMessage() {}
func (*DepositData) Descriptor() ([]byte, []int) {
return fileDescriptor_e719e7d82cfa7b0d, []int{15}
return fileDescriptor_e719e7d82cfa7b0d, []int{16}
}
func (m *DepositData) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1711,7 +1774,7 @@ func (m *ProposerSlashing) Reset() { *m = ProposerSlashing{} }
func (m *ProposerSlashing) String() string { return proto.CompactTextString(m) }
func (*ProposerSlashing) ProtoMessage() {}
func (*ProposerSlashing) Descriptor() ([]byte, []int) {
return fileDescriptor_e719e7d82cfa7b0d, []int{16}
return fileDescriptor_e719e7d82cfa7b0d, []int{17}
}
func (m *ProposerSlashing) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1807,7 +1870,7 @@ func (m *AttesterSlashing) Reset() { *m = AttesterSlashing{} }
func (m *AttesterSlashing) String() string { return proto.CompactTextString(m) }
func (*AttesterSlashing) ProtoMessage() {}
func (*AttesterSlashing) Descriptor() ([]byte, []int) {
return fileDescriptor_e719e7d82cfa7b0d, []int{17}
return fileDescriptor_e719e7d82cfa7b0d, []int{18}
}
func (m *AttesterSlashing) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1882,7 +1945,7 @@ func (m *Deposit) Reset() { *m = Deposit{} }
func (m *Deposit) String() string { return proto.CompactTextString(m) }
func (*Deposit) ProtoMessage() {}
func (*Deposit) Descriptor() ([]byte, []int) {
return fileDescriptor_e719e7d82cfa7b0d, []int{18}
return fileDescriptor_e719e7d82cfa7b0d, []int{19}
}
func (m *Deposit) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1969,7 +2032,7 @@ func (m *VoluntaryExit) Reset() { *m = VoluntaryExit{} }
func (m *VoluntaryExit) String() string { return proto.CompactTextString(m) }
func (*VoluntaryExit) ProtoMessage() {}
func (*VoluntaryExit) Descriptor() ([]byte, []int) {
return fileDescriptor_e719e7d82cfa7b0d, []int{19}
return fileDescriptor_e719e7d82cfa7b0d, []int{20}
}
func (m *VoluntaryExit) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -2036,7 +2099,7 @@ func (m *Transfer) Reset() { *m = Transfer{} }
func (m *Transfer) String() string { return proto.CompactTextString(m) }
func (*Transfer) ProtoMessage() {}
func (*Transfer) Descriptor() ([]byte, []int) {
return fileDescriptor_e719e7d82cfa7b0d, []int{20}
return fileDescriptor_e719e7d82cfa7b0d, []int{21}
}
func (m *Transfer) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -2129,7 +2192,7 @@ func (m *Eth1Data) Reset() { *m = Eth1Data{} }
func (m *Eth1Data) String() string { return proto.CompactTextString(m) }
func (*Eth1Data) ProtoMessage() {}
func (*Eth1Data) Descriptor() ([]byte, []int) {
return fileDescriptor_e719e7d82cfa7b0d, []int{21}
return fileDescriptor_e719e7d82cfa7b0d, []int{22}
}
func (m *Eth1Data) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -2207,7 +2270,7 @@ func (m *Eth1DataVote) Reset() { *m = Eth1DataVote{} }
func (m *Eth1DataVote) String() string { return proto.CompactTextString(m) }
func (*Eth1DataVote) ProtoMessage() {}
func (*Eth1DataVote) Descriptor() ([]byte, []int) {
return fileDescriptor_e719e7d82cfa7b0d, []int{22}
return fileDescriptor_e719e7d82cfa7b0d, []int{23}
}
func (m *Eth1DataVote) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -2262,7 +2325,7 @@ func (m *HistoricalBatch) Reset() { *m = HistoricalBatch{} }
func (m *HistoricalBatch) String() string { return proto.CompactTextString(m) }
func (*HistoricalBatch) ProtoMessage() {}
func (*HistoricalBatch) Descriptor() ([]byte, []int) {
return fileDescriptor_e719e7d82cfa7b0d, []int{23}
return fileDescriptor_e719e7d82cfa7b0d, []int{24}
}
func (m *HistoricalBatch) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -2320,7 +2383,7 @@ func (m *BeaconBlockHeader) Reset() { *m = BeaconBlockHeader{} }
func (m *BeaconBlockHeader) String() string { return proto.CompactTextString(m) }
func (*BeaconBlockHeader) ProtoMessage() {}
func (*BeaconBlockHeader) Descriptor() ([]byte, []int) {
return fileDescriptor_e719e7d82cfa7b0d, []int{24}
return fileDescriptor_e719e7d82cfa7b0d, []int{25}
}
func (m *BeaconBlockHeader) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -2391,6 +2454,7 @@ func init() {
proto.RegisterType((*PendingAttestation)(nil), "ethereum.beacon.p2p.v1.PendingAttestation")
proto.RegisterType((*Attestation)(nil), "ethereum.beacon.p2p.v1.Attestation")
proto.RegisterType((*AttestationData)(nil), "ethereum.beacon.p2p.v1.AttestationData")
proto.RegisterType((*AttestationTarget)(nil), "ethereum.beacon.p2p.v1.AttestationTarget")
proto.RegisterType((*AttestationDataAndCustodyBit)(nil), "ethereum.beacon.p2p.v1.AttestationDataAndCustodyBit")
proto.RegisterType((*IndexedAttestation)(nil), "ethereum.beacon.p2p.v1.IndexedAttestation")
proto.RegisterType((*Validator)(nil), "ethereum.beacon.p2p.v1.Validator")
@@ -2416,186 +2480,187 @@ func init() {
func init() { proto.RegisterFile("proto/beacon/p2p/v1/types.proto", fileDescriptor_e719e7d82cfa7b0d) }
var fileDescriptor_e719e7d82cfa7b0d = []byte{
// 2850 bytes of a gzipped FileDescriptorProto
// 2880 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x5a, 0x49, 0x6c, 0x23, 0xc7,
0xd5, 0xfe, 0x49, 0x49, 0x23, 0xe9, 0x89, 0x12, 0xc9, 0xd2, 0xd6, 0xd6, 0x2c, 0x9a, 0xe1, 0x8c,
0xd5, 0xfe, 0x49, 0x4a, 0x23, 0xe9, 0x91, 0x12, 0xc9, 0xd2, 0xd6, 0xd6, 0x2c, 0x9a, 0xe1, 0x8c,
0x67, 0xb3, 0x4d, 0x99, 0x34, 0x6c, 0xe3, 0xff, 0xfd, 0x5b, 0x18, 0x69, 0x46, 0xf6, 0xc8, 0xbb,
0x5b, 0xb2, 0xe7, 0xc7, 0x7f, 0xe9, 0x34, 0xd9, 0x45, 0xaa, 0x47, 0x54, 0x37, 0xd1, 0xd5, 0x94,
0x47, 0x41, 0xae, 0x39, 0xd8, 0x59, 0xcf, 0xb9, 0x25, 0x76, 0xb6, 0x7b, 0x2e, 0xd9, 0x0e, 0x41,
0x36, 0x67, 0x73, 0x9c, 0x00, 0x09, 0x10, 0x20, 0x07, 0xc3, 0x40, 0x80, 0x8c, 0xe3, 0x1c, 0x92,
0xdc, 0x83, 0xa0, 0xea, 0x55, 0x75, 0x55, 0x37, 0x49, 0x8d, 0x64, 0xfb, 0xa6, 0x7e, 0x5b, 0xbd,
0x57, 0x55, 0xef, 0x7b, 0xef, 0x15, 0x05, 0xcb, 0xdd, 0x28, 0x8c, 0xc3, 0x95, 0x06, 0x75, 0x9b,
0x61, 0xb0, 0xd2, 0xad, 0x77, 0x57, 0xf6, 0x6b, 0x2b, 0xf1, 0x41, 0x97, 0xb2, 0xaa, 0xe0, 0x90,
0x05, 0x1a, 0xef, 0xd0, 0x88, 0xf6, 0xf6, 0xaa, 0x28, 0x53, 0xed, 0xd6, 0xbb, 0xd5, 0xfd, 0xda,
0xd2, 0x49, 0x54, 0x6c, 0x86, 0x7b, 0x7b, 0x61, 0xb0, 0xb2, 0x47, 0x19, 0x73, 0xdb, 0x4a, 0xa9,
0xf2, 0xde, 0x1c, 0x4c, 0xad, 0x0b, 0xf1, 0xad, 0xd8, 0x8d, 0x29, 0xa9, 0x40, 0xa1, 0x4d, 0x03,
0xca, 0x7c, 0xe6, 0xc4, 0xfe, 0x1e, 0xb5, 0xee, 0x8e, 0x9f, 0xcd, 0x5d, 0x1e, 0xb5, 0xa7, 0x24,
0x71, 0xdb, 0xdf, 0xa3, 0xa4, 0x06, 0xa3, 0xad, 0x30, 0xda, 0xb5, 0x3e, 0xe0, 0xbc, 0xa9, 0xfa,
0xa9, 0xea, 0xe0, 0x85, 0xab, 0x4f, 0x85, 0xd1, 0xae, 0x2d, 0x44, 0xc9, 0x2c, 0x8c, 0xb2, 0x4e,
0x18, 0x5b, 0x7f, 0x43, 0x73, 0xe2, 0x83, 0xbc, 0x0c, 0x64, 0xdf, 0xed, 0xf8, 0x9e, 0x1b, 0x87,
0x91, 0x13, 0xd1, 0xb6, 0xcf, 0xe2, 0xe8, 0xc0, 0xfa, 0x5d, 0xf1, 0xec, 0xc8, 0xe5, 0xa9, 0xfa,
0xb9, 0x61, 0x56, 0x5f, 0x55, 0x2a, 0x76, 0x39, 0xd1, 0xb6, 0xa5, 0x32, 0x39, 0x09, 0x13, 0x0d,
0xb7, 0xe3, 0x06, 0x4d, 0xca, 0xac, 0xdf, 0x73, 0x43, 0xa3, 0x76, 0x42, 0x20, 0x2b, 0x30, 0xdb,
0x71, 0x63, 0xca, 0x62, 0x27, 0x72, 0x03, 0xcf, 0x0d, 0x9d, 0x3d, 0xff, 0x0e, 0x65, 0xd6, 0x77,
0x17, 0xcf, 0x8e, 0x5c, 0x2e, 0xd8, 0x65, 0xe4, 0xd9, 0x82, 0xf5, 0x3c, 0xe7, 0x90, 0x87, 0x80,
0x48, 0x05, 0x16, 0xbb, 0x51, 0xec, 0xb0, 0x1d, 0x37, 0xf2, 0xac, 0xef, 0x2d, 0x8a, 0x18, 0x4a,
0xc8, 0xda, 0xe2, 0x9c, 0x2d, 0xce, 0x20, 0xbb, 0x70, 0xb2, 0x1b, 0xd1, 0x7d, 0x3f, 0xec, 0x31,
0x87, 0x76, 0xc3, 0xe6, 0x8e, 0xe3, 0xc6, 0x5c, 0xc4, 0x8d, 0xfd, 0x30, 0x60, 0xd6, 0x57, 0x97,
0x45, 0x60, 0x57, 0x87, 0x05, 0xf6, 0x12, 0x0d, 0x3c, 0x3f, 0x68, 0xaf, 0x69, 0x1d, 0xfb, 0x3e,
0x65, 0x6f, 0x83, 0x9b, 0x33, 0x38, 0x8c, 0xf8, 0xb0, 0xd4, 0xec, 0x45, 0x11, 0x0d, 0xe2, 0x41,
0x6b, 0x7d, 0xed, 0xf8, 0x6b, 0x59, 0xd2, 0x5c, 0xff, 0x52, 0xff, 0x0d, 0x56, 0x12, 0xd7, 0xed,
0x1e, 0x8b, 0xfd, 0x96, 0x4f, 0x3d, 0x5c, 0xd5, 0x7a, 0x73, 0x59, 0x6c, 0xc6, 0x82, 0x12, 0x78,
0x46, 0xf1, 0x85, 0x19, 0xf2, 0x38, 0x2c, 0x2a, 0x2f, 0xb3, 0x9a, 0x6f, 0xa1, 0xe6, 0xbc, 0xe4,
0xf7, 0x2b, 0x0e, 0x58, 0x33, 0x0a, 0xc3, 0xd8, 0xfa, 0x3a, 0x57, 0x2c, 0xd8, 0xf3, 0x7d, 0x4b,
0xda, 0x61, 0x18, 0x93, 0x47, 0x61, 0xa1, 0x7f, 0x45, 0xa1, 0xf7, 0x0d, 0xd4, 0x9b, 0xcb, 0x2e,
0x28, 0xd4, 0x1e, 0x83, 0x05, 0x29, 0xde, 0x14, 0x51, 0x3b, 0x0d, 0x3f, 0x6e, 0xf9, 0xb4, 0xe3,
0x59, 0xdf, 0x94, 0x7e, 0xa6, 0xd8, 0xeb, 0x92, 0x4b, 0x2e, 0x43, 0xb1, 0xe5, 0x07, 0x6e, 0xc7,
0xff, 0x74, 0x12, 0xd8, 0xb7, 0x50, 0x61, 0x26, 0xa1, 0x63, 0x44, 0x17, 0x41, 0x53, 0xd0, 0xa1,
0x6f, 0xa3, 0x43, 0xd3, 0x09, 0x59, 0x78, 0xf2, 0x32, 0x10, 0x15, 0x40, 0x33, 0x0a, 0x19, 0xeb,
0xf8, 0xc1, 0x2e, 0xb3, 0x5e, 0xbf, 0x74, 0x78, 0x56, 0x5c, 0x57, 0xa2, 0x76, 0x59, 0x6a, 0x27,
0x14, 0x46, 0xb6, 0x60, 0x36, 0xd9, 0x4c, 0xc3, 0xe6, 0x1b, 0x47, 0xb6, 0x49, 0x94, 0xba, 0x61,
0x54, 0x27, 0x47, 0xa3, 0x13, 0x36, 0x77, 0x45, 0x48, 0xcc, 0xfa, 0xdc, 0x25, 0x91, 0x4c, 0x32,
0x39, 0xd6, 0x39, 0x87, 0x47, 0x95, 0xc9, 0xa5, 0x98, 0x4a, 0xf1, 0xcf, 0xa7, 0xc4, 0x05, 0x04,
0xa1, 0xf8, 0xff, 0xc0, 0x7d, 0x52, 0xdc, 0x6d, 0xc6, 0xfe, 0x3e, 0x75, 0xfc, 0xc0, 0xa3, 0x77,
0xa4, 0xd6, 0x17, 0x50, 0x6b, 0x01, 0x25, 0xd6, 0x84, 0xc0, 0x26, 0xe7, 0xa3, 0xee, 0xe3, 0xb0,
0xa8, 0x96, 0xea, 0xb8, 0x6c, 0x87, 0x7a, 0x4e, 0x82, 0x09, 0x5f, 0xbc, 0x24, 0x30, 0x61, 0x5e,
0xae, 0x87, 0xec, 0x75, 0x05, 0x10, 0xff, 0x9f, 0x00, 0x04, 0x86, 0xb4, 0x43, 0x5d, 0x8f, 0x46,
0xd6, 0x97, 0x2e, 0x09, 0x9c, 0xbb, 0x32, 0x6c, 0x9f, 0x10, 0x3f, 0x45, 0xac, 0x37, 0x85, 0x86,
0xc2, 0x12, 0x83, 0x44, 0xae, 0x42, 0x69, 0xc7, 0x67, 0x71, 0x18, 0xf9, 0x4d, 0xb7, 0x23, 0xe3,
0xf8, 0x32, 0xc6, 0x51, 0xd4, 0x0c, 0x0c, 0xe0, 0x59, 0x90, 0x1b, 0xe2, 0xd0, 0x78, 0xa7, 0xe6,
0x78, 0x6e, 0xec, 0x5a, 0xff, 0xa8, 0x0a, 0x27, 0xce, 0x0e, 0x73, 0x62, 0x23, 0xde, 0xa9, 0xdd,
0x70, 0x63, 0xd7, 0x9e, 0x41, 0x55, 0xf5, 0x4d, 0x9e, 0x87, 0x62, 0x62, 0xc5, 0xd9, 0x0f, 0x63,
0xca, 0xac, 0x7f, 0x56, 0xc5, 0xc1, 0x5f, 0xb8, 0x97, 0xad, 0x57, 0xc3, 0x98, 0xda, 0xd3, 0xd4,
0xf8, 0x62, 0xe4, 0x02, 0x4c, 0x7b, 0xb4, 0x1b, 0x32, 0x3f, 0xc6, 0x23, 0xb1, 0xfe, 0x55, 0x15,
0xd7, 0xbd, 0x20, 0xa9, 0xe2, 0x1c, 0xc8, 0x33, 0xb0, 0xdc, 0x0f, 0xed, 0x4e, 0xaf, 0xeb, 0xf1,
0xa3, 0xc7, 0x34, 0xf9, 0xd1, 0x2a, 0xd7, 0x5b, 0xcf, 0x5b, 0x39, 0xfb, 0x54, 0x1f, 0x90, 0xbf,
0x22, 0x24, 0x31, 0x71, 0x6e, 0xc2, 0x99, 0xe4, 0xf6, 0xb2, 0x9d, 0x5e, 0xab, 0xd5, 0xf1, 0x83,
0x76, 0x0a, 0x91, 0x7f, 0xac, 0x4d, 0x25, 0x08, 0xbc, 0xa5, 0x24, 0x0d, 0x80, 0x7e, 0x0a, 0x4e,
0xab, 0xd4, 0x1a, 0x6c, 0xe8, 0x27, 0xda, 0x90, 0x42, 0xd7, 0x41, 0x76, 0x9e, 0x34, 0x00, 0x51,
0x1b, 0xc2, 0xb0, 0x7e, 0xaa, 0x4d, 0x2c, 0xf4, 0xf9, 0x82, 0x01, 0x3d, 0xa1, 0x41, 0x31, 0xab,
0xfd, 0x33, 0xad, 0x3d, 0x9f, 0x75, 0xe0, 0xd0, 0xdd, 0xa0, 0xd4, 0x73, 0x76, 0x5c, 0xb6, 0xf3,
0x48, 0xdd, 0xfa, 0x39, 0xb7, 0x51, 0x18, 0xb6, 0x1b, 0x94, 0x7a, 0x37, 0x85, 0xdc, 0x90, 0xdd,
0x30, 0x0c, 0xbd, 0xad, 0x0d, 0xf5, 0xef, 0x86, 0xb6, 0xf3, 0x20, 0x14, 0xb3, 0xd8, 0xfe, 0x0b,
0x1d, 0xc6, 0xcc, 0xed, 0x34, 0xb0, 0x5f, 0x85, 0x99, 0x0c, 0x2e, 0xff, 0x52, 0x2f, 0x33, 0x7d,
0x3b, 0x05, 0xca, 0xab, 0x09, 0x08, 0xe8, 0xec, 0x97, 0xce, 0x31, 0xeb, 0x57, 0xab, 0x3c, 0x79,
0x70, 0xa3, 0x51, 0x2a, 0x81, 0x00, 0x74, 0x8c, 0x19, 0xfa, 0x1a, 0xa2, 0x12, 0xfd, 0x5f, 0xf7,
0xe9, 0x27, 0x68, 0xa5, 0xf4, 0xaf, 0xc1, 0x52, 0xc3, 0x8d, 0x9b, 0x02, 0x41, 0xfa, 0x0d, 0xfc,
0x46, 0x1b, 0x58, 0x94, 0x62, 0x7d, 0x16, 0xb6, 0x40, 0x42, 0x81, 0x89, 0xbb, 0xef, 0xac, 0x1e,
0x11, 0x77, 0x85, 0x6d, 0x09, 0x05, 0x06, 0xf2, 0x7e, 0x2a, 0x81, 0xa9, 0x54, 0xcd, 0xff, 0xed,
0xea, 0x71, 0x6b, 0xbe, 0xb0, 0x2f, 0x61, 0x39, 0x55, 0xf1, 0x9f, 0x85, 0x82, 0xb9, 0x71, 0xd6,
0xbb, 0xab, 0x02, 0x7c, 0xce, 0x1f, 0x01, 0x01, 0x85, 0xcd, 0x29, 0x63, 0x43, 0x2b, 0x5d, 0x18,
0xe5, 0x9d, 0x20, 0xb9, 0x02, 0xa5, 0xe4, 0xe6, 0xee, 0xd3, 0x88, 0xf9, 0x61, 0x60, 0xe5, 0x04,
0x76, 0x14, 0x15, 0xfd, 0x55, 0x24, 0x93, 0x4b, 0x50, 0x54, 0x57, 0x53, 0x49, 0xe6, 0xb1, 0xa8,
0x4a, 0xb2, 0x12, 0x9c, 0x83, 0x31, 0xbc, 0x71, 0x23, 0x82, 0x8d, 0x1f, 0x95, 0x3f, 0xe6, 0x80,
0xf4, 0x47, 0x4b, 0x6a, 0x30, 0xe7, 0xb6, 0xdb, 0x11, 0x6d, 0x67, 0x2a, 0x7c, 0x4e, 0x94, 0xe1,
0x59, 0x83, 0x97, 0x94, 0xf7, 0x27, 0x60, 0x54, 0xa0, 0x6f, 0x5e, 0xc4, 0x7f, 0x69, 0x58, 0xfc,
0xc6, 0x2a, 0x02, 0x83, 0x85, 0x12, 0xb9, 0x1f, 0x66, 0xfc, 0xa0, 0xd9, 0xe9, 0x71, 0x4f, 0x1d,
0xd1, 0xfe, 0xa2, 0x97, 0xd3, 0x09, 0x75, 0x8b, 0xb7, 0xc1, 0x57, 0xa0, 0xd4, 0xec, 0xb1, 0x38,
0xf4, 0x0e, 0xb4, 0x4b, 0xa3, 0xc2, 0xa5, 0xa2, 0xa4, 0x2b, 0x77, 0x2a, 0x7f, 0xca, 0xc1, 0x94,
0x19, 0x91, 0x72, 0x2f, 0xf7, 0x51, 0xdc, 0x1b, 0xb6, 0x1d, 0xf9, 0xe1, 0xdb, 0x31, 0xc8, 0xd5,
0x91, 0x81, 0xae, 0xf2, 0x66, 0x5b, 0x59, 0xa0, 0x0e, 0xf3, 0xdb, 0x81, 0x1b, 0xf7, 0x22, 0x2a,
0x03, 0x23, 0x09, 0x6b, 0x4b, 0x71, 0x2a, 0xdf, 0x1f, 0x83, 0x62, 0xc6, 0x51, 0x42, 0xe4, 0xd8,
0x90, 0x33, 0xa6, 0x86, 0xab, 0x50, 0xc6, 0xe8, 0x8c, 0x9c, 0x94, 0x3e, 0x17, 0x1b, 0xfa, 0x1e,
0x0a, 0x00, 0x39, 0x07, 0x05, 0x16, 0xf6, 0xa2, 0xa6, 0xaa, 0x39, 0xb8, 0xff, 0x53, 0x48, 0x43,
0x3c, 0x5a, 0x06, 0xf9, 0x89, 0x86, 0x46, 0x85, 0x04, 0x20, 0x49, 0xd8, 0x58, 0x86, 0xa9, 0xd8,
0x8d, 0xda, 0x34, 0x46, 0x81, 0x31, 0x14, 0x40, 0x92, 0x10, 0x98, 0x83, 0x31, 0xac, 0x1e, 0x27,
0xf0, 0x0e, 0x8a, 0x0f, 0xf2, 0x98, 0xd1, 0xc0, 0x26, 0xb9, 0x8f, 0x26, 0xc6, 0xd3, 0xfd, 0xab,
0x6e, 0xb3, 0xb8, 0xb5, 0x2a, 0xcc, 0x6a, 0x71, 0x51, 0xb3, 0x85, 0xce, 0x84, 0xd0, 0x29, 0x27,
0x2c, 0x71, 0x8e, 0x5c, 0xfe, 0x1a, 0x2c, 0x61, 0xff, 0xdf, 0x08, 0x7b, 0x81, 0xe7, 0x46, 0x07,
0x26, 0x48, 0x59, 0x7f, 0x1d, 0x4f, 0xb0, 0x75, 0x51, 0x88, 0xad, 0x4b, 0x29, 0x0d, 0x52, 0xe4,
0xe5, 0xa4, 0xdb, 0x48, 0xac, 0xe3, 0xd8, 0x77, 0x64, 0x88, 0x2a, 0x66, 0x20, 0x6a, 0x50, 0x49,
0x10, 0xc3, 0xe2, 0xe0, 0x92, 0xb0, 0x0e, 0x27, 0xb5, 0x74, 0x1f, 0xd0, 0xe2, 0xcc, 0x88, 0x31,
0x58, 0x89, 0x5c, 0x06, 0x69, 0xc9, 0xff, 0x82, 0xd5, 0x77, 0x2b, 0x94, 0x81, 0x0f, 0xb5, 0x81,
0xf9, 0xcc, 0x0d, 0x91, 0xda, 0xd7, 0x60, 0x69, 0xc0, 0xa6, 0x2b, 0xfd, 0xbf, 0x1b, 0x9b, 0xd8,
0x77, 0x00, 0x68, 0xa1, 0xf2, 0x19, 0x38, 0x95, 0xb9, 0xbc, 0x6b, 0x81, 0x77, 0x3d, 0xc9, 0x89,
0x8f, 0x97, 0xa9, 0xcb, 0x30, 0x65, 0xa4, 0x9d, 0xb8, 0xec, 0x13, 0x36, 0xe8, 0x8c, 0xab, 0xfc,
0x21, 0x07, 0x44, 0x54, 0x3f, 0xea, 0xa5, 0x01, 0x6f, 0xde, 0xd0, 0x73, 0x1e, 0xe6, 0x65, 0xd4,
0xe7, 0x6d, 0x70, 0x4e, 0x74, 0xc1, 0x44, 0x5b, 0x78, 0x78, 0x13, 0x39, 0x59, 0x95, 0x5a, 0xa2,
0x92, 0xcf, 0xaa, 0xd4, 0x94, 0x8a, 0x0a, 0x6d, 0xe4, 0xa3, 0x84, 0x76, 0x0a, 0x26, 0xb3, 0xe0,
0xa0, 0x09, 0x95, 0xb7, 0xc6, 0x60, 0x32, 0x99, 0xf7, 0xc9, 0x02, 0x9c, 0xe8, 0xf6, 0x1a, 0xbb,
0xf4, 0x40, 0x22, 0xb6, 0xfc, 0xe2, 0x23, 0xdf, 0x6b, 0x7e, 0xbc, 0xe3, 0x45, 0xee, 0x6b, 0x6e,
0xc7, 0x69, 0x46, 0xd4, 0xa3, 0x41, 0xec, 0xbb, 0x1d, 0x26, 0x61, 0x61, 0x5e, 0x73, 0xaf, 0x6b,
0x26, 0xb9, 0x06, 0xa7, 0xc4, 0x6c, 0x81, 0xf0, 0x47, 0x3b, 0x7e, 0xdb, 0x6f, 0xf8, 0x1d, 0x3f,
0x3e, 0x48, 0x81, 0xc5, 0x92, 0x96, 0xd9, 0xd0, 0x22, 0x78, 0x71, 0xaf, 0x40, 0xc9, 0xb4, 0x20,
0xb4, 0x10, 0x40, 0x8a, 0x86, 0x96, 0x10, 0x3d, 0x0d, 0x40, 0xef, 0xf8, 0x72, 0x56, 0x97, 0x20,
0x32, 0xc9, 0x29, 0xc8, 0x7e, 0x08, 0x48, 0xe2, 0x64, 0xa3, 0xa3, 0xe0, 0x0a, 0x01, 0xa5, 0x6c,
0x72, 0x50, 0xdc, 0x82, 0x71, 0x39, 0xda, 0x08, 0x30, 0x99, 0xb0, 0xd5, 0x27, 0x79, 0x00, 0xca,
0xb4, 0xd5, 0xa2, 0x38, 0x33, 0xc9, 0xb1, 0x47, 0x80, 0xc7, 0xa8, 0x5d, 0x4a, 0x18, 0x72, 0xe0,
0x21, 0x55, 0x28, 0x19, 0x1b, 0x87, 0x6b, 0xde, 0xd5, 0x79, 0x5a, 0xd4, 0x4c, 0x5c, 0xf6, 0x32,
0x4c, 0xab, 0x89, 0xaa, 0x2f, 0xa9, 0x0b, 0x92, 0x83, 0x92, 0xaf, 0x40, 0x81, 0x9f, 0x75, 0x8f,
0x39, 0xad, 0x8e, 0xdb, 0x66, 0x98, 0xc3, 0x33, 0xf5, 0x87, 0xee, 0xf9, 0xa8, 0x53, 0xdd, 0x12,
0x6a, 0x4f, 0x71, 0x2d, 0x6c, 0x25, 0x98, 0x26, 0x90, 0xa7, 0xe1, 0xf4, 0xe0, 0x93, 0x1e, 0x90,
0xea, 0x27, 0x07, 0x9e, 0xba, 0x4c, 0xd7, 0xe7, 0x60, 0xca, 0x58, 0x88, 0x14, 0x61, 0x7c, 0xf3,
0x85, 0xcd, 0xed, 0xcd, 0xb5, 0xe7, 0x4a, 0xff, 0xb5, 0x94, 0x9f, 0xc8, 0x91, 0x05, 0x98, 0x41,
0xc2, 0xf6, 0xc6, 0x0d, 0x67, 0xe3, 0xff, 0x36, 0xb7, 0x4b, 0x39, 0x41, 0x9f, 0x83, 0xc2, 0xad,
0xcd, 0xed, 0x9b, 0x37, 0xec, 0xb5, 0x5b, 0x6b, 0xeb, 0xcf, 0x6d, 0x94, 0xf2, 0x9c, 0x5a, 0xe9,
0xc0, 0xa2, 0x18, 0x0c, 0x6c, 0xea, 0x32, 0x7e, 0x79, 0xf7, 0x68, 0x10, 0xdb, 0xb4, 0x19, 0x46,
0x1e, 0xef, 0x64, 0xf4, 0x20, 0x84, 0x03, 0x13, 0x16, 0xb3, 0x99, 0x84, 0x8c, 0x13, 0x53, 0x52,
0x45, 0xf2, 0x66, 0x15, 0x51, 0x05, 0x70, 0x44, 0x17, 0xc0, 0xca, 0x9b, 0x39, 0x98, 0xd4, 0x50,
0x9b, 0x74, 0x40, 0x39, 0xa3, 0x03, 0x22, 0xd7, 0x8d, 0x29, 0x21, 0x5d, 0x7d, 0xd4, 0x4e, 0x61,
0x6a, 0x9c, 0x1c, 0x58, 0x84, 0x24, 0x2a, 0x3e, 0x71, 0x28, 0x2a, 0x62, 0xdd, 0x1f, 0x0a, 0x88,
0xaf, 0x8f, 0xa8, 0x87, 0x45, 0x01, 0xb6, 0xc3, 0x4a, 0x79, 0xd7, 0x15, 0x5d, 0x5e, 0x7f, 0x29,
0x47, 0x86, 0x2e, 0xe5, 0xa7, 0x01, 0xf4, 0xc3, 0x81, 0x5c, 0x7c, 0x92, 0xa9, 0x07, 0x03, 0x0e,
0x42, 0x8d, 0xd0, 0x3b, 0x10, 0xe9, 0x77, 0x08, 0x08, 0x99, 0x8d, 0x6a, 0xe8, 0x1d, 0xd8, 0x42,
0x29, 0x0d, 0x42, 0x63, 0x19, 0x10, 0xe2, 0xb9, 0x29, 0xbd, 0x34, 0xc3, 0xbf, 0x8b, 0x55, 0xbc,
0x84, 0x2c, 0x63, 0xd7, 0x1e, 0x80, 0xb2, 0x76, 0x54, 0x49, 0x7f, 0x80, 0xd2, 0xc5, 0xc4, 0x61,
0x29, 0x7c, 0x01, 0xa6, 0xe5, 0x5b, 0x64, 0x44, 0xf7, 0xa9, 0xdb, 0x91, 0xc5, 0xce, 0x2e, 0x20,
0xd5, 0x16, 0x44, 0xb2, 0x0a, 0x93, 0xfa, 0x21, 0xe0, 0xc3, 0xf1, 0x23, 0x3e, 0x04, 0x4c, 0xa8,
0xc1, 0xbd, 0xf2, 0xc3, 0x51, 0x28, 0x66, 0x22, 0x27, 0xe7, 0xb3, 0x2b, 0xe7, 0x06, 0x2c, 0xfc,
0xa4, 0xb9, 0x70, 0xfe, 0xb8, 0xeb, 0x92, 0xa7, 0xa1, 0x90, 0x9a, 0x50, 0x46, 0xc4, 0x80, 0x72,
0xfe, 0x08, 0x15, 0xc2, 0x4e, 0x29, 0x92, 0x5b, 0x40, 0xba, 0x51, 0xd8, 0x0d, 0x19, 0x8d, 0xf0,
0x4d, 0xc7, 0x0f, 0xda, 0xcc, 0x1a, 0x15, 0xe6, 0x2e, 0x0f, 0x9d, 0x77, 0xa4, 0xc6, 0x96, 0x54,
0xb0, 0xcb, 0xdd, 0x0c, 0x45, 0x18, 0xc6, 0x85, 0x52, 0x86, 0xc7, 0x0e, 0x37, 0xbc, 0x26, 0x35,
0xb4, 0x61, 0x37, 0x43, 0xe1, 0x45, 0x71, 0x42, 0x3e, 0x88, 0x30, 0xeb, 0x84, 0x30, 0xb7, 0x3c,
0xcc, 0xdc, 0x0d, 0x94, 0xb3, 0x13, 0x05, 0xf2, 0x02, 0x14, 0xf7, 0xc3, 0x4e, 0x2f, 0x88, 0x79,
0x3b, 0xc7, 0x8b, 0x04, 0xb3, 0xc6, 0x85, 0x8d, 0xfb, 0x87, 0xe2, 0xa7, 0x12, 0xdf, 0xb8, 0xe3,
0xc7, 0xf6, 0xcc, 0xbe, 0xf9, 0xc9, 0xe7, 0xe0, 0xc9, 0x38, 0x72, 0x03, 0xd6, 0xa2, 0x11, 0xb3,
0x26, 0x84, 0xa5, 0xa1, 0xc7, 0xb8, 0x2d, 0x05, 0x6d, 0xad, 0x52, 0xf9, 0x4a, 0x0e, 0x0a, 0x37,
0xd4, 0xf3, 0x4e, 0xb7, 0x17, 0x0f, 0xad, 0xc4, 0x55, 0x98, 0xed, 0x46, 0x61, 0xd8, 0x72, 0xc2,
0x96, 0xd3, 0x0d, 0x19, 0xa3, 0x2c, 0x99, 0xdd, 0x0a, 0x62, 0xfb, 0xc3, 0xd6, 0x8b, 0xad, 0x97,
0x12, 0x06, 0x59, 0xbf, 0x17, 0x9e, 0x63, 0x9e, 0x1f, 0x0a, 0xe5, 0xb7, 0x81, 0xe0, 0x49, 0xbb,
0x1d, 0x3e, 0x4c, 0x50, 0x6f, 0xe8, 0xe4, 0x30, 0x18, 0x62, 0xf9, 0x3c, 0xd1, 0xd7, 0x32, 0xca,
0xa1, 0xa6, 0x91, 0xee, 0x13, 0x2b, 0x7f, 0xce, 0xc1, 0x9c, 0x38, 0x63, 0x5e, 0x8a, 0xcd, 0x4e,
0xeb, 0x01, 0x28, 0xa7, 0x60, 0xde, 0xe8, 0xb2, 0x4a, 0x26, 0xd0, 0x8b, 0x86, 0x69, 0xd0, 0x14,
0x95, 0x1f, 0x3c, 0x45, 0x7d, 0xac, 0xde, 0xea, 0xd8, 0x23, 0xd8, 0x67, 0xf3, 0x30, 0x25, 0xcf,
0x59, 0x6c, 0xe2, 0x27, 0xdc, 0x70, 0x2d, 0xc0, 0x09, 0x77, 0x2f, 0xec, 0x05, 0xaa, 0x9c, 0xc9,
0xaf, 0xc3, 0x7b, 0x40, 0xf2, 0x82, 0xf9, 0xe0, 0xd8, 0xed, 0xc5, 0x6a, 0x36, 0xb9, 0x70, 0x8f,
0x7c, 0x12, 0x37, 0x15, 0x5b, 0x13, 0xcf, 0xbc, 0xbb, 0xe7, 0x60, 0x32, 0xf6, 0xf7, 0xf8, 0x76,
0xed, 0x75, 0xcd, 0x06, 0x46, 0x53, 0x2b, 0x7f, 0x19, 0x81, 0x52, 0x16, 0x3d, 0xf8, 0x34, 0x9f,
0x60, 0x90, 0x59, 0xc8, 0xa7, 0x15, 0x15, 0xeb, 0xf8, 0x0d, 0x98, 0xc0, 0x67, 0x63, 0xa7, 0x26,
0x11, 0xf3, 0x18, 0xef, 0xc6, 0xe3, 0xa8, 0x5a, 0x33, 0xac, 0xd4, 0xe5, 0xd9, 0x1f, 0xdf, 0x4a,
0x9d, 0xdc, 0x82, 0x62, 0x57, 0xa6, 0x06, 0xd6, 0xef, 0x9a, 0xda, 0xbc, 0xab, 0x87, 0x83, 0xa6,
0x99, 0x4a, 0xf8, 0x30, 0xa7, 0xec, 0x70, 0x4a, 0x8d, 0x3c, 0x0a, 0x73, 0x89, 0xe1, 0xe4, 0xa4,
0x9c, 0x9a, 0x2c, 0x73, 0xf8, 0xac, 0xd4, 0x35, 0x2c, 0x09, 0x7e, 0xad, 0xdf, 0x1f, 0x39, 0xdc,
0x7d, 0x4c, 0x7f, 0xea, 0x43, 0xfc, 0x49, 0xb5, 0x83, 0xfd, 0xfe, 0xd4, 0x2b, 0x6f, 0x8c, 0x40,
0x29, 0x0b, 0xe6, 0xe4, 0x45, 0x98, 0x36, 0x6a, 0x8f, 0x53, 0x93, 0x23, 0xdb, 0x50, 0x0f, 0xfb,
0xe7, 0xae, 0x54, 0xf1, 0xaa, 0x65, 0x0d, 0xd6, 0xe5, 0xb5, 0xf8, 0xa8, 0x06, 0xeb, 0xc4, 0x87,
0x45, 0xa6, 0x40, 0xc8, 0x49, 0xfb, 0x2a, 0x8f, 0xf7, 0xc1, 0x61, 0xb6, 0x07, 0x81, 0x17, 0x0e,
0xc6, 0x6c, 0x00, 0xa7, 0x36, 0x7c, 0xa9, 0xba, 0xfa, 0xf5, 0xf7, 0x13, 0x5a, 0xaa, 0x5e, 0xf9,
0x77, 0x0e, 0xc6, 0x65, 0xea, 0x72, 0xa4, 0x16, 0xc5, 0x42, 0x40, 0x68, 0xc1, 0xc6, 0x0f, 0x4e,
0xc5, 0xc4, 0x93, 0xf8, 0x2d, 0x3e, 0xc8, 0xe3, 0x29, 0x88, 0x3c, 0x7f, 0x0f, 0x54, 0x30, 0xe0,
0xf1, 0x51, 0x98, 0xdb, 0xa3, 0xd1, 0x6e, 0x87, 0x3a, 0x58, 0xb3, 0xd4, 0xbb, 0xee, 0xdd, 0xf1,
0xe4, 0x5d, 0x97, 0xa0, 0xc0, 0x4b, 0x9c, 0xaf, 0x9e, 0x74, 0x57, 0xa0, 0x2c, 0xd5, 0xe2, 0x88,
0xca, 0xdf, 0xa5, 0x4c, 0x1c, 0x29, 0x22, 0x77, 0x3b, 0xa2, 0xf8, 0x9b, 0x14, 0xb9, 0x08, 0x0a,
0x80, 0xb0, 0x8f, 0x32, 0xde, 0x33, 0xa6, 0x3c, 0xed, 0x55, 0xa5, 0x03, 0xd3, 0xa9, 0x32, 0x3e,
0xa4, 0xb5, 0x1f, 0x30, 0x51, 0xe4, 0x07, 0x4e, 0x14, 0x29, 0x58, 0x1d, 0xc9, 0x8e, 0xd6, 0xdf,
0xc9, 0xc1, 0x84, 0xaa, 0xf5, 0x1c, 0x99, 0x19, 0x0d, 0x3c, 0x1a, 0xc9, 0xa5, 0xe4, 0x17, 0x37,
0x11, 0xd1, 0xa6, 0xdf, 0xf5, 0x69, 0x10, 0xcb, 0x55, 0x34, 0x61, 0x28, 0x9e, 0x97, 0x60, 0xa4,
0x45, 0xa9, 0x9c, 0x84, 0xf9, 0x9f, 0x49, 0x35, 0x1e, 0x33, 0xaa, 0xb1, 0x2e, 0x2e, 0x27, 0x52,
0xc5, 0x25, 0xe5, 0xf6, 0x78, 0xd6, 0xed, 0x77, 0x72, 0x30, 0x91, 0xfc, 0xb4, 0x75, 0x4e, 0xef,
0xac, 0x98, 0x0a, 0xb0, 0x4a, 0xa9, 0x4d, 0x15, 0x73, 0xc1, 0x79, 0x5d, 0x3d, 0x9a, 0xc2, 0xd5,
0x7c, 0xea, 0xd7, 0xaa, 0xeb, 0xc2, 0xe1, 0xd3, 0x00, 0xc6, 0x00, 0x22, 0xb7, 0x2a, 0xa9, 0xfd,
0xe4, 0x11, 0x98, 0x35, 0x97, 0x19, 0xf0, 0xb6, 0x56, 0x36, 0x96, 0x94, 0x9d, 0xfd, 0x45, 0x28,
0xc8, 0x1f, 0x11, 0xcd, 0x79, 0x01, 0x4f, 0x5d, 0x30, 0x64, 0x4b, 0xd1, 0x81, 0x82, 0xf9, 0x73,
0x5b, 0xba, 0xe5, 0xce, 0x1d, 0xbb, 0xe5, 0x3e, 0x0d, 0xb0, 0x1f, 0xc6, 0x34, 0x15, 0xec, 0x24,
0xa7, 0x88, 0x48, 0x2b, 0x5b, 0x50, 0xbc, 0x99, 0xfc, 0xd8, 0xb8, 0xee, 0xc6, 0xf8, 0x00, 0x6a,
0xfe, 0x80, 0x8b, 0x19, 0x07, 0x0d, 0xfd, 0xcb, 0xed, 0x32, 0x4c, 0x99, 0x3f, 0xd9, 0xe6, 0x51,
0x20, 0x99, 0x64, 0x58, 0xe5, 0x07, 0x39, 0x28, 0xf7, 0x55, 0xa1, 0x81, 0x1d, 0x58, 0xd5, 0xf8,
0x21, 0xba, 0x6f, 0xe4, 0x2b, 0x2b, 0xd6, 0x91, 0x87, 0xbe, 0x8b, 0x80, 0x1d, 0x9a, 0xc3, 0xa7,
0x38, 0xfd, 0x7e, 0x5b, 0xb0, 0xa7, 0x1b, 0xc9, 0x84, 0xc7, 0xe5, 0x0e, 0x9d, 0xef, 0xd6, 0x0b,
0x6f, 0xbf, 0x7f, 0x26, 0xf7, 0xee, 0xfb, 0x67, 0x72, 0xef, 0xbd, 0x7f, 0x26, 0xd7, 0x38, 0x21,
0xfe, 0x2f, 0xe6, 0x91, 0xff, 0x04, 0x00, 0x00, 0xff, 0xff, 0xe3, 0x5d, 0xa4, 0xca, 0x6f, 0x23,
0x00, 0x00,
0x5b, 0xb2, 0xe7, 0xc7, 0x7f, 0xe9, 0x34, 0xd9, 0x45, 0xaa, 0x47, 0x14, 0x9b, 0xe8, 0x6a, 0xca,
0xa3, 0x20, 0xd7, 0x1c, 0xec, 0xac, 0xe7, 0xdc, 0x12, 0x3b, 0xdb, 0x3d, 0x97, 0x6c, 0x87, 0x20,
0x9b, 0xb3, 0x39, 0x4e, 0x80, 0x04, 0x08, 0x90, 0x83, 0x61, 0x20, 0x40, 0xc6, 0x71, 0x0e, 0x49,
0xee, 0x41, 0x50, 0xf5, 0xaa, 0xba, 0xaa, 0x9b, 0xa4, 0x46, 0xb2, 0x7d, 0x53, 0xbf, 0xad, 0xde,
0xab, 0xaa, 0xf7, 0xbd, 0xf7, 0x8a, 0x82, 0xe5, 0x5e, 0x18, 0x44, 0xc1, 0x4a, 0x83, 0xba, 0xcd,
0xa0, 0xbb, 0xd2, 0xab, 0xf7, 0x56, 0xf6, 0x6b, 0x2b, 0xd1, 0x41, 0x8f, 0xb2, 0xaa, 0xe0, 0x90,
0x05, 0x1a, 0xed, 0xd0, 0x90, 0xf6, 0xf7, 0xaa, 0x28, 0x53, 0xed, 0xd5, 0x7b, 0xd5, 0xfd, 0xda,
0xd2, 0x49, 0x54, 0x6c, 0x06, 0x7b, 0x7b, 0x41, 0x77, 0x65, 0x8f, 0x32, 0xe6, 0xb6, 0x95, 0x52,
0xe5, 0xbd, 0x39, 0xc8, 0xaf, 0x0b, 0xf1, 0xad, 0xc8, 0x8d, 0x28, 0xa9, 0x40, 0xa1, 0x4d, 0xbb,
0x94, 0xf9, 0xcc, 0x89, 0xfc, 0x3d, 0x6a, 0xdd, 0x9d, 0x38, 0x9b, 0xb9, 0x3c, 0x66, 0xe7, 0x25,
0x71, 0xdb, 0xdf, 0xa3, 0xa4, 0x06, 0x63, 0xad, 0x20, 0xdc, 0xb5, 0x3e, 0xe0, 0xbc, 0x7c, 0xfd,
0x54, 0x75, 0xf8, 0xc2, 0xd5, 0xa7, 0x82, 0x70, 0xd7, 0x16, 0xa2, 0x64, 0x16, 0xc6, 0x58, 0x27,
0x88, 0xac, 0xbf, 0xa1, 0x39, 0xf1, 0x41, 0x5e, 0x06, 0xb2, 0xef, 0x76, 0x7c, 0xcf, 0x8d, 0x82,
0xd0, 0x09, 0x69, 0xdb, 0x67, 0x51, 0x78, 0x60, 0xfd, 0xae, 0x78, 0x36, 0x77, 0x39, 0x5f, 0x3f,
0x37, 0xca, 0xea, 0xab, 0x4a, 0xc5, 0x2e, 0xc7, 0xda, 0xb6, 0x54, 0x26, 0x27, 0x61, 0xb2, 0xe1,
0x76, 0xdc, 0x6e, 0x93, 0x32, 0xeb, 0xf7, 0xdc, 0xd0, 0x98, 0x1d, 0x13, 0xc8, 0x0a, 0xcc, 0x76,
0xdc, 0x88, 0xb2, 0xc8, 0x09, 0xdd, 0xae, 0xe7, 0x06, 0xce, 0x9e, 0x7f, 0x87, 0x32, 0xeb, 0xbb,
0x8b, 0x67, 0x73, 0x97, 0x0b, 0x76, 0x19, 0x79, 0xb6, 0x60, 0x3d, 0xcf, 0x39, 0xe4, 0x21, 0x20,
0x52, 0x81, 0x45, 0x6e, 0x18, 0x39, 0x6c, 0xc7, 0x0d, 0x3d, 0xeb, 0x7b, 0x8b, 0x22, 0x86, 0x12,
0xb2, 0xb6, 0x38, 0x67, 0x8b, 0x33, 0xc8, 0x2e, 0x9c, 0xec, 0x85, 0x74, 0xdf, 0x0f, 0xfa, 0xcc,
0xa1, 0xbd, 0xa0, 0xb9, 0xe3, 0xb8, 0x11, 0x17, 0x71, 0x23, 0x3f, 0xe8, 0x32, 0xeb, 0xab, 0xcb,
0x22, 0xb0, 0xab, 0xa3, 0x02, 0x7b, 0x89, 0x76, 0x3d, 0xbf, 0xdb, 0x5e, 0xd3, 0x3a, 0xf6, 0x7d,
0xca, 0xde, 0x06, 0x37, 0x67, 0x70, 0x18, 0xf1, 0x61, 0xa9, 0xd9, 0x0f, 0x43, 0xda, 0x8d, 0x86,
0xad, 0xf5, 0xb5, 0xe3, 0xaf, 0x65, 0x49, 0x73, 0x83, 0x4b, 0xfd, 0x37, 0x58, 0x71, 0x5c, 0xb7,
0xfb, 0x2c, 0xf2, 0x5b, 0x3e, 0xf5, 0x70, 0x55, 0xeb, 0xcd, 0x65, 0xb1, 0x19, 0x0b, 0x4a, 0xe0,
0x19, 0xc5, 0x17, 0x66, 0xc8, 0xe3, 0xb0, 0xa8, 0xbc, 0x4c, 0x6b, 0xbe, 0x85, 0x9a, 0xf3, 0x92,
0x3f, 0xa8, 0x38, 0x64, 0xcd, 0x30, 0x08, 0x22, 0xeb, 0xeb, 0x5c, 0xb1, 0x60, 0xcf, 0x0f, 0x2c,
0x69, 0x07, 0x41, 0x44, 0x1e, 0x85, 0x85, 0xc1, 0x15, 0x85, 0xde, 0x37, 0x50, 0x6f, 0x2e, 0xbd,
0xa0, 0x50, 0x7b, 0x0c, 0x16, 0xa4, 0x78, 0x53, 0x44, 0xed, 0x34, 0xfc, 0xa8, 0xe5, 0xd3, 0x8e,
0x67, 0x7d, 0x53, 0xfa, 0x99, 0x60, 0xaf, 0x4b, 0x2e, 0xb9, 0x0c, 0xc5, 0x96, 0xdf, 0x75, 0x3b,
0xfe, 0xa7, 0xe3, 0xc0, 0xbe, 0x85, 0x0a, 0x33, 0x31, 0x1d, 0x23, 0xba, 0x08, 0x9a, 0x82, 0x0e,
0x7d, 0x1b, 0x1d, 0x9a, 0x8e, 0xc9, 0xc2, 0x93, 0x97, 0x81, 0xa8, 0x00, 0x9a, 0x61, 0xc0, 0x58,
0xc7, 0xef, 0xee, 0x32, 0xeb, 0xf5, 0x4b, 0x87, 0x67, 0xc5, 0x75, 0x25, 0x6a, 0x97, 0xa5, 0x76,
0x4c, 0x61, 0x64, 0x0b, 0x66, 0xe3, 0xcd, 0x34, 0x6c, 0xbe, 0x71, 0x64, 0x9b, 0x44, 0xa9, 0x1b,
0x46, 0x75, 0x72, 0x34, 0x3a, 0x41, 0x73, 0x57, 0x84, 0xc4, 0xac, 0xcf, 0x5d, 0x12, 0xc9, 0x24,
0x93, 0x63, 0x9d, 0x73, 0x78, 0x54, 0xa9, 0x5c, 0x8a, 0xa8, 0x14, 0xff, 0x7c, 0x42, 0x5c, 0x40,
0x10, 0x8a, 0xff, 0x0f, 0xdc, 0x27, 0xc5, 0xdd, 0x66, 0xe4, 0xef, 0x53, 0xc7, 0xef, 0x7a, 0xf4,
0x8e, 0xd4, 0xfa, 0x02, 0x6a, 0x2d, 0xa0, 0xc4, 0x9a, 0x10, 0xd8, 0xe4, 0x7c, 0xd4, 0x7d, 0x1c,
0x16, 0xd5, 0x52, 0x1d, 0x97, 0xed, 0x50, 0xcf, 0x89, 0x31, 0xe1, 0x8b, 0x97, 0x04, 0x26, 0xcc,
0xcb, 0xf5, 0x90, 0xbd, 0xae, 0x00, 0xe2, 0xff, 0x63, 0x80, 0xc0, 0x90, 0x76, 0xa8, 0xeb, 0xd1,
0xd0, 0xfa, 0xd2, 0x25, 0x81, 0x73, 0x57, 0x46, 0xed, 0x13, 0xe2, 0xa7, 0x88, 0xf5, 0xa6, 0xd0,
0x50, 0x58, 0x62, 0x90, 0xc8, 0x55, 0x28, 0xed, 0xf8, 0x2c, 0x0a, 0x42, 0xbf, 0xe9, 0x76, 0x64,
0x1c, 0x5f, 0xc6, 0x38, 0x8a, 0x9a, 0x81, 0x01, 0x3c, 0x0b, 0x72, 0x43, 0x1c, 0x1a, 0xed, 0xd4,
0x1c, 0xcf, 0x8d, 0x5c, 0xeb, 0x1f, 0x55, 0xe1, 0xc4, 0xd9, 0x51, 0x4e, 0x6c, 0x44, 0x3b, 0xb5,
0x1b, 0x6e, 0xe4, 0xda, 0x33, 0xa8, 0xaa, 0xbe, 0xc9, 0xf3, 0x50, 0x8c, 0xad, 0x38, 0xfb, 0x41,
0x44, 0x99, 0xf5, 0xcf, 0xaa, 0x38, 0xf8, 0x0b, 0xf7, 0xb2, 0xf5, 0x6a, 0x10, 0x51, 0x7b, 0x9a,
0x1a, 0x5f, 0x8c, 0x5c, 0x80, 0x69, 0x8f, 0xf6, 0x02, 0xe6, 0x47, 0x78, 0x24, 0xd6, 0xbf, 0xaa,
0xe2, 0xba, 0x17, 0x24, 0x55, 0x9c, 0x03, 0x79, 0x06, 0x96, 0x07, 0xa1, 0xdd, 0xe9, 0xf7, 0x3c,
0x7e, 0xf4, 0x98, 0x26, 0x3f, 0x5a, 0xe5, 0x7a, 0xeb, 0x59, 0x2b, 0x63, 0x9f, 0x1a, 0x00, 0xf2,
0x57, 0x84, 0x24, 0x26, 0xce, 0x4d, 0x38, 0x13, 0xdf, 0x5e, 0xb6, 0xd3, 0x6f, 0xb5, 0x3a, 0x7e,
0xb7, 0x9d, 0x40, 0xe4, 0x1f, 0x6b, 0x53, 0x31, 0x02, 0x6f, 0x29, 0x49, 0x03, 0xa0, 0x9f, 0x82,
0xd3, 0x2a, 0xb5, 0x86, 0x1b, 0xfa, 0x89, 0x36, 0xa4, 0xd0, 0x75, 0x98, 0x9d, 0x27, 0x0d, 0x40,
0xd4, 0x86, 0x30, 0xac, 0x9f, 0x6a, 0x13, 0x0b, 0x03, 0xbe, 0x60, 0x40, 0x4f, 0x68, 0x50, 0x4c,
0x6b, 0xff, 0x4c, 0x6b, 0xcf, 0xa7, 0x1d, 0x38, 0x74, 0x37, 0x28, 0xf5, 0x9c, 0x1d, 0x97, 0xed,
0x3c, 0x52, 0xb7, 0x7e, 0xce, 0x6d, 0x14, 0x46, 0xed, 0x06, 0xa5, 0xde, 0x4d, 0x21, 0x37, 0x62,
0x37, 0x0c, 0x43, 0x6f, 0x6b, 0x43, 0x83, 0xbb, 0xa1, 0xed, 0x3c, 0x08, 0xc5, 0x34, 0xb6, 0xff,
0x42, 0x87, 0x31, 0x73, 0x3b, 0x09, 0xec, 0x57, 0x61, 0x26, 0x85, 0xcb, 0xbf, 0xd4, 0xcb, 0x4c,
0xdf, 0x4e, 0x80, 0xf2, 0x6a, 0x0c, 0x02, 0x3a, 0xfb, 0xa5, 0x73, 0xcc, 0xfa, 0xd5, 0x2a, 0x4f,
0x1e, 0xdc, 0x68, 0x94, 0x8a, 0x21, 0x00, 0x1d, 0x63, 0x86, 0xbe, 0x86, 0xa8, 0x58, 0xff, 0xd7,
0x03, 0xfa, 0x31, 0x5a, 0x29, 0xfd, 0x6b, 0xb0, 0xd4, 0x70, 0xa3, 0xa6, 0x40, 0x90, 0x41, 0x03,
0xbf, 0xd1, 0x06, 0x16, 0xa5, 0xd8, 0x80, 0x85, 0x2d, 0x90, 0x50, 0x60, 0xe2, 0xee, 0x3b, 0xab,
0x47, 0xc4, 0x5d, 0x61, 0x5b, 0x42, 0x81, 0x81, 0xbc, 0x9f, 0x8a, 0x61, 0x2a, 0x51, 0xf3, 0x7f,
0xbb, 0x7a, 0xdc, 0x9a, 0x2f, 0xec, 0x4b, 0x58, 0x4e, 0x54, 0xfc, 0x67, 0xa1, 0x60, 0x6e, 0x9c,
0xf5, 0xee, 0xaa, 0x00, 0x9f, 0xf3, 0x47, 0x40, 0x40, 0x61, 0x33, 0x6f, 0x6c, 0x68, 0xa5, 0x07,
0x63, 0xbc, 0x13, 0x24, 0x57, 0xa0, 0x14, 0xdf, 0xdc, 0x7d, 0x1a, 0x32, 0x3f, 0xe8, 0x5a, 0x19,
0x81, 0x1d, 0x45, 0x45, 0x7f, 0x15, 0xc9, 0xe4, 0x12, 0x14, 0xd5, 0xd5, 0x54, 0x92, 0x59, 0x2c,
0xaa, 0x92, 0xac, 0x04, 0xe7, 0x60, 0x1c, 0x6f, 0x5c, 0x4e, 0xb0, 0xf1, 0xa3, 0xf2, 0xc7, 0x0c,
0x90, 0xc1, 0x68, 0x49, 0x0d, 0xe6, 0xdc, 0x76, 0x3b, 0xa4, 0xed, 0x54, 0x85, 0xcf, 0x88, 0x32,
0x3c, 0x6b, 0xf0, 0xe2, 0xf2, 0xfe, 0x04, 0x8c, 0x09, 0xf4, 0xcd, 0x8a, 0xf8, 0x2f, 0x8d, 0x8a,
0xdf, 0x58, 0x45, 0x60, 0xb0, 0x50, 0x22, 0xf7, 0xc3, 0x8c, 0xdf, 0x6d, 0x76, 0xfa, 0xdc, 0x53,
0x47, 0xb4, 0xbf, 0xe8, 0xe5, 0x74, 0x4c, 0xdd, 0xe2, 0x6d, 0xf0, 0x15, 0x28, 0x35, 0xfb, 0x2c,
0x0a, 0xbc, 0x03, 0xed, 0xd2, 0x98, 0x70, 0xa9, 0x28, 0xe9, 0xca, 0x9d, 0xca, 0x9f, 0x32, 0x90,
0x37, 0x23, 0x52, 0xee, 0x65, 0x3e, 0x8a, 0x7b, 0xa3, 0xb6, 0x23, 0x3b, 0x7a, 0x3b, 0x86, 0xb9,
0x9a, 0x1b, 0xea, 0x2a, 0x6f, 0xb6, 0x95, 0x05, 0xea, 0x30, 0xbf, 0xdd, 0x75, 0xa3, 0x7e, 0x48,
0x65, 0x60, 0x24, 0x66, 0x6d, 0x29, 0x4e, 0xe5, 0xfb, 0xe3, 0x50, 0x4c, 0x39, 0x4a, 0x88, 0x1c,
0x1b, 0x32, 0xc6, 0xd4, 0x70, 0x15, 0xca, 0x18, 0x9d, 0x91, 0x93, 0xd2, 0xe7, 0x62, 0x43, 0xdf,
0x43, 0x01, 0x20, 0xe7, 0xa0, 0xc0, 0x82, 0x7e, 0xd8, 0x54, 0x35, 0x07, 0xf7, 0x3f, 0x8f, 0x34,
0xc4, 0xa3, 0x65, 0x90, 0x9f, 0x68, 0x68, 0x4c, 0x48, 0x00, 0x92, 0x84, 0x8d, 0x65, 0xc8, 0x47,
0x6e, 0xd8, 0xa6, 0x11, 0x0a, 0x8c, 0xa3, 0x00, 0x92, 0x84, 0xc0, 0x1c, 0x8c, 0x63, 0xf5, 0x38,
0x81, 0x77, 0x50, 0x7c, 0x90, 0xc7, 0x8c, 0x06, 0x36, 0xce, 0x7d, 0x34, 0x31, 0x91, 0xec, 0x5f,
0x75, 0x9b, 0xc5, 0xad, 0x55, 0x61, 0x56, 0x8b, 0x8b, 0x9a, 0x2d, 0x74, 0x26, 0x85, 0x4e, 0x39,
0x66, 0x89, 0x73, 0xe4, 0xf2, 0xd7, 0x60, 0x09, 0xfb, 0xff, 0x46, 0xd0, 0xef, 0x7a, 0x6e, 0x78,
0x60, 0x82, 0x94, 0xf5, 0xd7, 0x89, 0x18, 0x5b, 0x17, 0x85, 0xd8, 0xba, 0x94, 0xd2, 0x20, 0x45,
0x5e, 0x8e, 0xbb, 0x8d, 0xd8, 0x3a, 0x8e, 0x7d, 0x47, 0x86, 0xa8, 0x62, 0x0a, 0xa2, 0x86, 0x95,
0x04, 0x31, 0x2c, 0x0e, 0x2f, 0x09, 0xeb, 0x70, 0x52, 0x4b, 0x0f, 0x00, 0x2d, 0xce, 0x8c, 0x18,
0x83, 0x15, 0xcb, 0xa5, 0x90, 0x96, 0xfc, 0x2f, 0x58, 0x03, 0xb7, 0x42, 0x19, 0xf8, 0x50, 0x1b,
0x98, 0x4f, 0xdd, 0x10, 0xa9, 0x7d, 0x0d, 0x96, 0x86, 0x6c, 0xba, 0xd2, 0xff, 0xbb, 0xb1, 0x89,
0x03, 0x07, 0x80, 0x16, 0x2a, 0x6d, 0x28, 0x1b, 0x97, 0x77, 0x5b, 0xdc, 0x8e, 0xa1, 0xd7, 0xf7,
0x34, 0xc0, 0xc0, 0xbd, 0x9d, 0x6a, 0xc4, 0x37, 0x76, 0x19, 0xf2, 0x3d, 0x57, 0x00, 0x9f, 0xe0,
0x63, 0x72, 0x01, 0x92, 0xb8, 0x40, 0xe5, 0x33, 0x70, 0x2a, 0x95, 0x25, 0x6b, 0x5d, 0xef, 0x7a,
0x9c, 0x7c, 0x1f, 0x0f, 0x12, 0x96, 0x21, 0x6f, 0xe4, 0xb7, 0xf0, 0x6e, 0xd2, 0x06, 0x9d, 0xda,
0x95, 0x3f, 0x64, 0x80, 0x88, 0x32, 0x4b, 0xbd, 0x24, 0xb2, 0xce, 0x1b, 0x7a, 0xce, 0xc3, 0xbc,
0x5e, 0xfb, 0xbc, 0xdf, 0xce, 0x88, 0x76, 0x9b, 0x68, 0x0b, 0x0f, 0x6f, 0x22, 0x27, 0xad, 0x52,
0x8b, 0x55, 0xb2, 0x69, 0x95, 0x9a, 0x52, 0x51, 0xa1, 0xe5, 0x3e, 0x4a, 0x68, 0xa7, 0x60, 0x2a,
0x8d, 0x42, 0x9a, 0x50, 0x79, 0x6b, 0x1c, 0xa6, 0xe2, 0x87, 0x05, 0xb2, 0x00, 0x27, 0x7a, 0xfd,
0xc6, 0x2e, 0x3d, 0x90, 0xa5, 0x41, 0x7e, 0xf1, 0xd9, 0xf2, 0x35, 0x3f, 0xda, 0xf1, 0x42, 0xf7,
0x35, 0xb7, 0xe3, 0x34, 0x43, 0xea, 0xd1, 0x6e, 0xe4, 0xbb, 0x1d, 0x26, 0xcf, 0x71, 0x5e, 0x73,
0xaf, 0x6b, 0x26, 0xb9, 0x06, 0xa7, 0xc4, 0x10, 0x83, 0x38, 0x4b, 0x3b, 0x7e, 0xdb, 0x6f, 0xf8,
0x1d, 0x3f, 0x3a, 0x48, 0xa0, 0xd2, 0x92, 0x96, 0xd9, 0xd0, 0x22, 0x98, 0x21, 0x57, 0xa0, 0x64,
0x5a, 0x10, 0x5a, 0x88, 0x54, 0x45, 0x43, 0x4b, 0x88, 0x9e, 0x06, 0xa0, 0x77, 0x7c, 0xf9, 0x28,
0x20, 0xd1, 0x6a, 0x8a, 0x53, 0x90, 0xfd, 0x10, 0x90, 0xd8, 0xc9, 0x46, 0x47, 0xe1, 0x22, 0x22,
0x57, 0xd9, 0xe4, 0xa0, 0xb8, 0x05, 0x13, 0x72, 0x86, 0x12, 0xa8, 0x35, 0x69, 0xab, 0x4f, 0xf2,
0x00, 0x94, 0x69, 0xab, 0x45, 0x71, 0x38, 0x93, 0xf3, 0x95, 0x40, 0xa9, 0x31, 0xbb, 0x14, 0x33,
0xe4, 0x64, 0x45, 0xaa, 0x50, 0x32, 0x36, 0x0e, 0xd7, 0xbc, 0xab, 0x01, 0xa1, 0xa8, 0x99, 0xb8,
0xec, 0x65, 0x98, 0x56, 0xa3, 0xdb, 0x00, 0x7a, 0x14, 0x24, 0x07, 0x25, 0x5f, 0x81, 0x02, 0x3f,
0xeb, 0x3e, 0x73, 0x5a, 0x1d, 0xb7, 0xcd, 0x10, 0x2c, 0x66, 0xea, 0x0f, 0xdd, 0xf3, 0xf5, 0xa8,
0xba, 0x25, 0xd4, 0x9e, 0xe2, 0x5a, 0xd8, 0xb3, 0x30, 0x4d, 0x20, 0x4f, 0xc3, 0xe9, 0xe1, 0x27,
0x3d, 0x04, 0x53, 0x4e, 0x0e, 0x3d, 0x75, 0x89, 0x0b, 0xcf, 0x41, 0xde, 0x58, 0x88, 0x14, 0x61,
0x62, 0xf3, 0x85, 0xcd, 0xed, 0xcd, 0xb5, 0xe7, 0x4a, 0xff, 0xb5, 0x94, 0x9d, 0xcc, 0x90, 0x05,
0x98, 0x41, 0xc2, 0xf6, 0xc6, 0x0d, 0x67, 0xe3, 0xff, 0x36, 0xb7, 0x4b, 0x19, 0x41, 0x9f, 0x83,
0xc2, 0xad, 0xcd, 0xed, 0x9b, 0x37, 0xec, 0xb5, 0x5b, 0x6b, 0xeb, 0xcf, 0x6d, 0x94, 0xb2, 0x9c,
0x5a, 0xe9, 0xc0, 0xa2, 0x98, 0x40, 0x6c, 0xea, 0x32, 0x7e, 0x79, 0xf7, 0x38, 0x2a, 0xd0, 0x66,
0x10, 0x7a, 0xbc, 0x65, 0xd2, 0x13, 0x17, 0x4e, 0x66, 0x08, 0x3b, 0x33, 0x31, 0x19, 0x47, 0xb3,
0xb8, 0x5c, 0x65, 0xcd, 0x72, 0xa5, 0xa0, 0x2a, 0xa7, 0xa1, 0xaa, 0xf2, 0x66, 0x06, 0xa6, 0x34,
0xa6, 0xc7, 0xad, 0x56, 0xc6, 0x68, 0xb5, 0xc8, 0x75, 0x63, 0x1c, 0x49, 0x96, 0x39, 0xb5, 0x53,
0x98, 0x1a, 0x27, 0x87, 0x56, 0x3b, 0x09, 0xbf, 0x4f, 0x1c, 0x0a, 0xbf, 0x88, 0x81, 0x23, 0x91,
0xf7, 0xf5, 0x9c, 0x7a, 0xc1, 0x14, 0xa8, 0x3e, 0xaa, 0x67, 0x90, 0xa8, 0x3a, 0xd8, 0x33, 0x20,
0x43, 0xf7, 0x0c, 0xa7, 0x01, 0xf4, 0x0b, 0x85, 0x5c, 0x7c, 0x8a, 0xa9, 0x97, 0x09, 0x0e, 0x42,
0x8d, 0xc0, 0x3b, 0x10, 0xe9, 0x77, 0x08, 0x08, 0x99, 0x1d, 0x71, 0xe0, 0x1d, 0xd8, 0x42, 0x29,
0x09, 0x42, 0xe3, 0x29, 0x10, 0xe2, 0xb9, 0x69, 0x60, 0xbf, 0x0a, 0xff, 0x2e, 0xb6, 0x0b, 0x25,
0x5d, 0x03, 0xe4, 0xae, 0x3d, 0x00, 0x65, 0xed, 0xa8, 0x92, 0xfe, 0x00, 0xa5, 0x8b, 0xb1, 0xc3,
0x52, 0xf8, 0x02, 0x4c, 0xcb, 0x47, 0xcf, 0x90, 0xee, 0x53, 0xb7, 0x23, 0xab, 0xaa, 0x5d, 0x40,
0xaa, 0x2d, 0x88, 0x64, 0x15, 0xa6, 0xf4, 0x8b, 0xc3, 0x87, 0x13, 0x47, 0x7c, 0x71, 0x98, 0x54,
0x2f, 0x04, 0x95, 0x1f, 0x8e, 0x41, 0x31, 0x15, 0x39, 0x39, 0x9f, 0x5e, 0x39, 0x33, 0x64, 0xe1,
0x27, 0xcd, 0x85, 0xb3, 0xc7, 0x5d, 0x97, 0x3c, 0x0d, 0x85, 0xc4, 0x28, 0x94, 0x13, 0x93, 0xd0,
0xf9, 0x23, 0x54, 0x08, 0x3b, 0xa1, 0x48, 0x6e, 0x01, 0xe9, 0x85, 0x41, 0x2f, 0x60, 0x34, 0xc4,
0xc7, 0x23, 0xbf, 0xdb, 0x66, 0xd6, 0x98, 0x30, 0x77, 0x79, 0xe4, 0x60, 0x25, 0x35, 0xb6, 0xa4,
0x82, 0x5d, 0xee, 0xa5, 0x28, 0xc2, 0x30, 0x2e, 0x94, 0x30, 0x3c, 0x7e, 0xb8, 0xe1, 0x35, 0xa9,
0xa1, 0x0d, 0xbb, 0x29, 0x0a, 0x2f, 0x8a, 0x93, 0xf2, 0xe5, 0x85, 0x59, 0x27, 0x84, 0xb9, 0xe5,
0x51, 0xe6, 0x6e, 0xa0, 0x9c, 0x1d, 0x2b, 0x90, 0x17, 0xa0, 0xb8, 0x1f, 0x74, 0xfa, 0xdd, 0x88,
0xf7, 0x8d, 0xbc, 0x48, 0x30, 0x6b, 0x42, 0xd8, 0xb8, 0x7f, 0x24, 0x7e, 0x2a, 0xf1, 0x8d, 0x3b,
0x7e, 0x64, 0xcf, 0xec, 0x9b, 0x9f, 0x7c, 0xe0, 0x9e, 0x8a, 0x42, 0xb7, 0xcb, 0x5a, 0x34, 0x64,
0xd6, 0xa4, 0xb0, 0x34, 0xf2, 0x18, 0xb7, 0xa5, 0xa0, 0xad, 0x55, 0x2a, 0x5f, 0xc9, 0x40, 0xe1,
0x86, 0x7a, 0x47, 0xea, 0xf5, 0xa3, 0x91, 0x95, 0xb8, 0x0a, 0xb3, 0xbd, 0x30, 0x08, 0x5a, 0x4e,
0xd0, 0x72, 0x7a, 0x01, 0x63, 0x94, 0xc5, 0x43, 0x62, 0x41, 0x6c, 0x7f, 0xd0, 0x7a, 0xb1, 0xf5,
0x52, 0xcc, 0x20, 0xeb, 0xf7, 0xc2, 0x73, 0xcc, 0xf3, 0x43, 0xa1, 0xfc, 0x36, 0x10, 0x3c, 0x69,
0xb7, 0xc3, 0xa7, 0x16, 0xea, 0x8d, 0x1c, 0x51, 0x86, 0x43, 0x2c, 0x1f, 0x5c, 0x06, 0x7a, 0x53,
0x39, 0x3d, 0x35, 0x92, 0x0d, 0x69, 0xe5, 0xcf, 0x19, 0x98, 0x13, 0x67, 0xcc, 0x4b, 0xb1, 0xd9,
0x69, 0x3d, 0x00, 0xe5, 0x04, 0xcc, 0x1b, 0x5d, 0x56, 0xc9, 0x04, 0x7a, 0xd1, 0x30, 0x0d, 0x1b,
0xd7, 0xb2, 0xc3, 0xc7, 0xb5, 0x8f, 0xd5, 0x5b, 0x1d, 0x7b, 0xd6, 0xfb, 0x6c, 0x16, 0xf2, 0xf2,
0x9c, 0xc5, 0x26, 0x7e, 0xc2, 0x0d, 0xd7, 0x02, 0x9c, 0x70, 0xf7, 0x82, 0x7e, 0x57, 0x95, 0x33,
0xf9, 0x75, 0x78, 0x0f, 0x48, 0x5e, 0x30, 0x5f, 0x36, 0x7b, 0xfd, 0x48, 0x0d, 0x41, 0x17, 0xee,
0x91, 0x4f, 0xe2, 0xa6, 0x62, 0x6b, 0xe2, 0x99, 0x77, 0xf7, 0x1c, 0x4c, 0x45, 0xfe, 0x1e, 0xdf,
0xae, 0xbd, 0x9e, 0xd9, 0xc0, 0x68, 0x6a, 0xe5, 0x2f, 0x39, 0x28, 0xa5, 0xd1, 0x83, 0xdc, 0x0f,
0x33, 0x31, 0x06, 0x99, 0x85, 0x7c, 0x5a, 0x51, 0xb1, 0x8e, 0xdf, 0x80, 0x49, 0x7c, 0x9f, 0x76,
0x6a, 0x12, 0x31, 0x8f, 0xf1, 0x40, 0x3d, 0x81, 0xaa, 0x35, 0xc3, 0x4a, 0x5d, 0x9e, 0xfd, 0xf1,
0xad, 0xd4, 0xc9, 0x2d, 0x28, 0xf6, 0x64, 0x6a, 0x60, 0xfd, 0xae, 0xa9, 0xcd, 0xbb, 0x7a, 0x38,
0x68, 0x9a, 0xa9, 0x84, 0x2f, 0x80, 0xca, 0x0e, 0xa7, 0xd4, 0xc8, 0xa3, 0x30, 0x17, 0x1b, 0x8e,
0x4f, 0xca, 0xa9, 0xc9, 0x32, 0x87, 0xef, 0x57, 0x3d, 0xc3, 0x92, 0xe0, 0xd7, 0x06, 0xfd, 0x91,
0x53, 0xe4, 0xc7, 0xf4, 0xa7, 0x3e, 0xc2, 0x9f, 0x44, 0x3b, 0x38, 0xe8, 0x4f, 0xbd, 0xf2, 0x46,
0x0e, 0x4a, 0x69, 0x30, 0x27, 0x2f, 0xc2, 0xb4, 0x51, 0x7b, 0x9c, 0x9a, 0x1c, 0xd9, 0x46, 0x7a,
0x38, 0x38, 0x77, 0x25, 0x8a, 0x57, 0x2d, 0x6d, 0xb0, 0x2e, 0xaf, 0xc5, 0x47, 0x35, 0x58, 0x27,
0x3e, 0x2c, 0x32, 0x05, 0x42, 0x4e, 0xd2, 0x57, 0x79, 0xbc, 0x0f, 0x8e, 0xb2, 0x3d, 0x0c, 0xbc,
0x70, 0x02, 0x67, 0x43, 0x38, 0xb5, 0xd1, 0x4b, 0xd5, 0xd5, 0xcf, 0xcc, 0x9f, 0xd0, 0x52, 0xf5,
0xca, 0xbf, 0x33, 0x30, 0x21, 0x53, 0x97, 0x23, 0xb5, 0x28, 0x16, 0x02, 0x42, 0x0b, 0x36, 0x7e,
0x70, 0x2a, 0x26, 0x9e, 0xc4, 0x6f, 0xf1, 0x41, 0x1e, 0x4f, 0x40, 0xe4, 0xf9, 0x7b, 0xa0, 0x82,
0x01, 0x8f, 0x8f, 0xc2, 0xdc, 0x1e, 0x0d, 0x77, 0x3b, 0xd4, 0xc1, 0x9a, 0xa5, 0x1e, 0x90, 0xef,
0x4e, 0xc4, 0x0f, 0xc8, 0x04, 0x05, 0x5e, 0xe2, 0x7c, 0xf5, 0x76, 0xbc, 0x02, 0x65, 0xa9, 0x16,
0x85, 0x54, 0xfe, 0x00, 0x66, 0xe2, 0x48, 0x11, 0xb9, 0xdb, 0x21, 0xc5, 0x1f, 0xbf, 0xc8, 0x45,
0x50, 0x00, 0x84, 0x7d, 0x94, 0xf1, 0x70, 0x92, 0xf7, 0xb4, 0x57, 0x95, 0x0e, 0x4c, 0x27, 0xca,
0xf8, 0x88, 0xd6, 0x7e, 0xc8, 0x44, 0x91, 0x1d, 0x3a, 0x51, 0x24, 0x60, 0x35, 0x97, 0x1e, 0xad,
0xbf, 0x93, 0x81, 0x49, 0x55, 0xeb, 0x39, 0x32, 0x33, 0xda, 0xf5, 0x68, 0x28, 0x97, 0x92, 0x5f,
0xdc, 0x44, 0x48, 0x9b, 0x7e, 0xcf, 0xa7, 0xdd, 0x48, 0xae, 0xa2, 0x09, 0x23, 0xf1, 0xbc, 0x04,
0xb9, 0x16, 0xa5, 0x72, 0x12, 0xe6, 0x7f, 0xc6, 0xd5, 0x78, 0xdc, 0xa8, 0xc6, 0xba, 0xb8, 0x9c,
0x48, 0x14, 0x97, 0x84, 0xdb, 0x13, 0x69, 0xb7, 0xdf, 0xc9, 0xc0, 0x64, 0xfc, 0x1b, 0xda, 0x39,
0xbd, 0xb3, 0x62, 0x2a, 0xc0, 0x2a, 0xa5, 0x36, 0x55, 0xcc, 0x05, 0xe7, 0x75, 0xf5, 0x68, 0x0a,
0x57, 0xb3, 0x89, 0x9f, 0xc5, 0xae, 0x0b, 0x87, 0x93, 0x8f, 0x3f, 0xb9, 0xf4, 0xe3, 0xcf, 0x23,
0x30, 0x6b, 0x2e, 0x33, 0xe4, 0x11, 0xaf, 0x6c, 0x2c, 0x29, 0x3b, 0xfb, 0x8b, 0x50, 0x90, 0xbf,
0x56, 0x9a, 0xf3, 0x02, 0x9e, 0xba, 0x60, 0xc8, 0x96, 0xa2, 0x03, 0x05, 0xf3, 0x77, 0xbd, 0x64,
0xcb, 0x9d, 0x39, 0x76, 0xcb, 0x7d, 0x1a, 0x60, 0x3f, 0x88, 0x68, 0x22, 0xd8, 0x29, 0x4e, 0x11,
0x91, 0x56, 0xb6, 0xa0, 0x78, 0x33, 0xfe, 0x55, 0x73, 0xdd, 0x8d, 0xf0, 0xa5, 0xd5, 0xfc, 0xa5,
0x18, 0x33, 0x0e, 0x1a, 0xfa, 0x27, 0xe2, 0x65, 0xc8, 0x9b, 0xbf, 0x0d, 0x67, 0x51, 0x20, 0x9e,
0x64, 0x58, 0xe5, 0x07, 0x19, 0x28, 0x0f, 0x54, 0xa1, 0xa1, 0x1d, 0x58, 0xd5, 0xf8, 0xc5, 0x7b,
0x60, 0xe4, 0x2b, 0x2b, 0xd6, 0x91, 0x87, 0xbe, 0x8b, 0x80, 0x1d, 0x9a, 0xc3, 0xa7, 0x38, 0xfd,
0x50, 0x5c, 0xb0, 0xa7, 0x1b, 0xf1, 0x84, 0xc7, 0xe5, 0x0e, 0x9d, 0xef, 0xd6, 0x0b, 0x6f, 0xbf,
0x7f, 0x26, 0xf3, 0xee, 0xfb, 0x67, 0x32, 0xef, 0xbd, 0x7f, 0x26, 0xd3, 0x38, 0x21, 0xfe, 0x01,
0xe7, 0x91, 0xff, 0x04, 0x00, 0x00, 0xff, 0xff, 0xee, 0x27, 0x24, 0x41, 0xd8, 0x23, 0x00, 0x00,
}
func (m *BeaconState) Marshal() (dAtA []byte, err error) {
@@ -3365,6 +3430,44 @@ func (m *AttestationData) MarshalTo(dAtA []byte) (int, error) {
return i, nil
}
func (m *AttestationTarget) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalTo(dAtA)
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *AttestationTarget) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
if m.Slot != 0 {
dAtA[i] = 0x8
i++
i = encodeVarintTypes(dAtA, i, uint64(m.Slot))
}
if len(m.BlockRoot) > 0 {
dAtA[i] = 0x12
i++
i = encodeVarintTypes(dAtA, i, uint64(len(m.BlockRoot)))
i += copy(dAtA[i:], m.BlockRoot)
}
if len(m.ParentRoot) > 0 {
dAtA[i] = 0x1a
i++
i = encodeVarintTypes(dAtA, i, uint64(len(m.ParentRoot)))
i += copy(dAtA[i:], m.ParentRoot)
}
if m.XXX_unrecognized != nil {
i += copy(dAtA[i:], m.XXX_unrecognized)
}
return i, nil
}
func (m *AttestationDataAndCustodyBit) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
@@ -4889,6 +4992,29 @@ func (m *AttestationData) Size() (n int) {
return n
}
func (m *AttestationTarget) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
if m.Slot != 0 {
n += 1 + sovTypes(uint64(m.Slot))
}
l = len(m.BlockRoot)
if l > 0 {
n += 1 + l + sovTypes(uint64(l))
}
l = len(m.ParentRoot)
if l > 0 {
n += 1 + l + sovTypes(uint64(l))
}
if m.XXX_unrecognized != nil {
n += len(m.XXX_unrecognized)
}
return n
}
func (m *AttestationDataAndCustodyBit) Size() (n int) {
if m == nil {
return 0
@@ -7801,6 +7927,147 @@ func (m *AttestationData) Unmarshal(dAtA []byte) error {
}
return nil
}
func (m *AttestationTarget) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTypes
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: AttestationTarget: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: AttestationTarget: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Slot", wireType)
}
m.Slot = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTypes
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.Slot |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field BlockRoot", wireType)
}
var byteLen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTypes
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
byteLen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if byteLen < 0 {
return ErrInvalidLengthTypes
}
postIndex := iNdEx + byteLen
if postIndex < 0 {
return ErrInvalidLengthTypes
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.BlockRoot = append(m.BlockRoot[:0], dAtA[iNdEx:postIndex]...)
if m.BlockRoot == nil {
m.BlockRoot = []byte{}
}
iNdEx = postIndex
case 3:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field ParentRoot", wireType)
}
var byteLen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTypes
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
byteLen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if byteLen < 0 {
return ErrInvalidLengthTypes
}
postIndex := iNdEx + byteLen
if postIndex < 0 {
return ErrInvalidLengthTypes
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.ParentRoot = append(m.ParentRoot[:0], dAtA[iNdEx:postIndex]...)
if m.ParentRoot == nil {
m.ParentRoot = []byte{}
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipTypes(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthTypes
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthTypes
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *AttestationDataAndCustodyBit) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0

View File

@@ -108,6 +108,12 @@ message AttestationData {
bytes crosslink_data_root_hash32 = 1005 [deprecated=true];
}
message AttestationTarget {
uint64 slot = 1;
bytes block_root = 2;
bytes parent_root = 3;
}
message AttestationDataAndCustodyBit {
AttestationData data = 1;
bool custody_bit = 2;

View File

@@ -47,16 +47,24 @@ var (
Usage: "Port used to listening and respond metrics for prometheus.",
Value: 8080,
}
// NoDiscovery specifies whether we are running a local network and have no need for connecting
// to the bootstrap nodes in the cloud
NoDiscovery = cli.BoolFlag{
Name: "no-discovery",
Usage: "Enable only local network p2p and do not connect to cloud bootstrap nodes.",
}
// BootstrapNode tells the beacon node which bootstrap node to connect to
BootstrapNode = cli.StringFlag{
Name: "bootstrap-node",
Usage: "The address of bootstrap node. Beacon node will connect for peer discovery via DHT",
Value: "/ip4/35.224.249.2/tcp/30001/p2p/QmQEe7o6hKJdGdSkJRh7WJzS6xrex5f4w2SPR6oWbJNriw",
}
// RelayNode tells the beacon node which relay node to connect to.
RelayNode = cli.StringFlag{
Name: "relay-node",
Usage: "The address of relay node. The beacon node will connect to the " +
"relay node and advertise their address via the relay node to other peers",
Value: "",
}
// P2PPort defines the port to be used by libp2p.
P2PPort = cli.IntFlag{
@@ -64,8 +72,8 @@ var (
Usage: "The port used by libp2p.",
Value: 12000,
}
// ClearDBFlag tells the beacon node to remove any previously stored data at the data directory.
ClearDBFlag = cli.BoolFlag{
// ClearDB tells the beacon node to remove any previously stored data at the data directory.
ClearDB = cli.BoolFlag{
Name: "clear-db",
Usage: "Clears any previously stored data at the data directory",
}

View File

@@ -30,8 +30,9 @@ type FeatureFlagConfig struct {
EnableCrosslinks bool // EnableCrosslinks in epoch processing.
EnableCheckBlockStateRoot bool // EnableCheckBlockStateRoot in block processing.
EnableHistoricalStatePruning bool // EnableHistoricalStatePruning when updating finalized states.
EnableBlockAncestorCache bool //EnableBlockAncestorCache for fork choice optimization.
DisableGossipSub bool // DisableGossipSub in p2p messaging.
EnableCommitteesCache bool // EnableCommitteesCache for state transition.
CacheTreeHash bool // CacheTreeHash determent whether tree hashes will be cached.
}
var featureConfig *FeatureFlagConfig
@@ -69,14 +70,14 @@ func ConfigureBeaconFeatures(ctx *cli.Context) {
log.Info("Enabled check block state root")
cfg.EnableCheckBlockStateRoot = true
}
if ctx.GlobalBool(CacheTreeHashFlag.Name) {
log.Info("Cache tree hashes for ssz")
cfg.CacheTreeHash = true
}
if ctx.GlobalBool(EnableHistoricalStatePruningFlag.Name) {
log.Info("Enabled historical state pruning")
cfg.EnableHistoricalStatePruning = true
}
if ctx.GlobalBool(EnableBlockAncestorCacheFlag.Name) {
log.Info("Enabled block ancestor cache")
cfg.EnableBlockAncestorCache = true
}
if ctx.GlobalBool(DisableGossipSubFlag.Name) {
log.Info("Disabled gossipsub, using floodsub")
cfg.DisableGossipSub = true
@@ -93,6 +94,10 @@ func ConfigureValidatorFeatures(ctx *cli.Context) {
log.Info("Verifying signatures for attestations")
cfg.VerifyAttestationSigs = true
}
if ctx.GlobalBool(CacheTreeHashFlag.Name) {
log.Info("Cache tree hashes for ssz")
cfg.CacheTreeHash = true
}
InitFeatureConfig(cfg)
}

View File

@@ -5,6 +5,11 @@ import (
)
var (
// CacheTreeHashFlag determines whether to cache tree hashes for ssz.
CacheTreeHashFlag = cli.BoolFlag{
Name: "enable-cache-tree-hash",
Usage: "Cache tree hashes for ssz",
}
// VerifyAttestationSigsFlag determines whether to verify signatures for attestations.
VerifyAttestationSigsFlag = cli.BoolFlag{
Name: "enable-attestation-signature-verification",
@@ -25,12 +30,6 @@ var (
Name: "enable-crosslinks",
Usage: "Enable crosslinks in epoch processing, default is disabled.",
}
// EnableBlockAncestorCacheFlag enables block ancestor cache for LMD GHOST fork choice optimization. I
// it is disabled by default.
EnableBlockAncestorCacheFlag = cli.BoolFlag{
Name: "enable-block-ancestor-cache",
Usage: "Enable block ancestor cache for fork choice optimization, default is disabled.",
}
// EnableCheckBlockStateRootFlag check block state root in block processing. It is disabled by default.
EnableCheckBlockStateRootFlag = cli.BoolFlag{
Name: "enable-check-block-state-root",
@@ -49,7 +48,9 @@ var (
)
// ValidatorFlags contains a list of all the feature flags that apply to the validator client.
var ValidatorFlags = []cli.Flag{}
var ValidatorFlags = []cli.Flag{
CacheTreeHashFlag,
}
// BeaconChainFlags contains a list of all the feature flags that apply to the beacon-chain client.
var BeaconChainFlags = []cli.Flag{
@@ -57,6 +58,6 @@ var BeaconChainFlags = []cli.Flag{
EnableCrosslinksFlag,
EnableCheckBlockStateRootFlag,
EnableHistoricalStatePruningFlag,
EnableBlockAncestorCacheFlag,
DisableGossipSubFlag,
CacheTreeHashFlag,
}

View File

@@ -35,6 +35,7 @@ go_test(
"//proto/beacon/p2p/v1:go_default_library",
"//shared/bls:go_default_library",
"//shared/bytesutil:go_default_library",
"//shared/featureconfig:go_default_library",
"//shared/params:go_default_library",
"//shared/ssz:go_default_library",
"//shared/testutil:go_default_library",

View File

@@ -8,11 +8,18 @@ import (
"github.com/gogo/protobuf/proto"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared/bls"
"github.com/prysmaticlabs/prysm/shared/featureconfig"
"github.com/prysmaticlabs/prysm/shared/keystore"
"github.com/prysmaticlabs/prysm/shared/params"
"github.com/prysmaticlabs/prysm/shared/ssz"
)
func init() {
featureconfig.InitFeatureConfig(&featureconfig.FeatureFlagConfig{
CacheTreeHash: false,
})
}
func TestDepositInput_GeneratesPb(t *testing.T) {
k1, err := keystore.NewKey(rand.Reader)
if err != nil {

View File

@@ -10,6 +10,8 @@ import (
"go.opencensus.io/trace"
)
const noMsgData = "message contains no data"
var log = logrus.WithField("prefix", "message-handler")
// SafelyHandleMessage will recover and log any panic that occurs from the
@@ -17,7 +19,7 @@ var log = logrus.WithField("prefix", "message-handler")
func SafelyHandleMessage(ctx context.Context, fn func(ctx context.Context, message proto.Message) error, msg proto.Message) {
defer func() {
if r := recover(); r != nil {
printedMsg := "message contains no data"
printedMsg := noMsgData
if msg != nil {
printedMsg = proto.MarshalTextString(msg)
}

View File

@@ -55,10 +55,12 @@ type Server struct {
topicMapping map[reflect.Type]string
bootstrapNode string
relayNodeAddr string
noDiscovery bool
}
// ServerConfig for peer to peer networking.
type ServerConfig struct {
NoDiscovery bool
BootstrapNodeAddr string
RelayNodeAddr string
Port int
@@ -112,6 +114,7 @@ func NewServer(cfg *ServerConfig) (*Server, error) {
topicMapping: make(map[reflect.Type]string),
bootstrapNode: cfg.BootstrapNodeAddr,
relayNodeAddr: cfg.RelayNodeAddr,
noDiscovery: cfg.NoDiscovery,
}, nil
}
@@ -139,7 +142,7 @@ func (s *Server) Start() {
defer span.End()
log.Info("Starting service")
if s.bootstrapNode != "" {
if !s.noDiscovery && s.bootstrapNode != "" {
if err := startDHTDiscovery(ctx, s.host, s.bootstrapNode); err != nil {
log.Errorf("Could not start peer discovery via DHT: %v", err)
}
@@ -149,8 +152,7 @@ func (s *Server) Start() {
log.Errorf("Failed to bootstrap DHT: %v", err)
}
}
if s.relayNodeAddr != "" {
if !s.noDiscovery && s.relayNodeAddr != "" {
if err := dialRelayNode(ctx, s.host, s.relayNodeAddr); err != nil {
log.Errorf("Could not dial relay node: %v", err)
}
@@ -161,7 +163,9 @@ func (s *Server) Start() {
return
}
startPeerWatcher(ctx, s.host, s.bootstrapNode, s.relayNodeAddr)
if !s.noDiscovery {
startPeerWatcher(ctx, s.host, s.bootstrapNode, s.relayNodeAddr)
}
}
// Stop the main p2p loop.

View File

@@ -28,7 +28,7 @@ func TestLifecycle(t *testing.T) {
t.Errorf("incorrect log. wanted: %s. got: %v", want, msg)
}
// The context should have been cancelled.
// The context should have been canceled.
if s.ctx.Err() == nil {
t.Error("Context was not cancelled")
}

View File

@@ -32,6 +32,9 @@ var _ = shared.Service(&Server{})
var _ = Broadcaster(&Server{})
var _ = Sender(&Server{})
const bar = "bar"
const testTopic = "test_topic"
func init() {
logrus.SetLevel(logrus.DebugLevel)
}
@@ -84,7 +87,7 @@ func TestBroadcast_OK(t *testing.T) {
func TestEmit_OK(t *testing.T) {
s, _ := NewServer(&ServerConfig{})
p := &testpb.TestMessage{Foo: "bar"}
p := &testpb.TestMessage{Foo: bar}
ctrl := gomock.NewController(t)
defer ctrl.Finish()
@@ -302,8 +305,8 @@ func TestRegisterTopic_WithoutAdapters(t *testing.T) {
if err != nil {
t.Fatalf("Failed to create new server: %v", err)
}
topic := "test_topic"
testMessage := &testpb.TestMessage{Foo: "bar"}
topic := testTopic
testMessage := &testpb.TestMessage{Foo: bar}
s.RegisterTopic(topic, testMessage)
@@ -316,8 +319,8 @@ func TestRegisterTopic_WithoutAdapters(t *testing.T) {
defer close(wait)
msg := <-ch
tmsg := msg.Data.(*testpb.TestMessage)
if tmsg.Foo != "bar" {
t.Errorf("Expected test message Foo: \"bar\". Got: %v", tmsg)
if tmsg.Foo != bar {
t.Errorf("Expected test message foo:\"bar\". Got: %v", tmsg)
}
}()
@@ -338,8 +341,8 @@ func TestRegisterTopic_WithAdapters(t *testing.T) {
if err != nil {
t.Fatalf("Failed to create new server: %v", err)
}
topic := "test_topic"
testMessage := &testpb.TestMessage{Foo: "bar"}
topic := testTopic
testMessage := &testpb.TestMessage{Foo: bar}
i := 0
var testAdapter Adapter = func(next Handler) Handler {
@@ -368,7 +371,7 @@ func TestRegisterTopic_WithAdapters(t *testing.T) {
defer close(wait)
msg := <-ch
tmsg := msg.Data.(*testpb.TestMessage)
if tmsg.Foo != "bar" {
if tmsg.Foo != bar {
t.Errorf("Expected test message Foo: \"bar\". Got: %v", tmsg)
}
}()
@@ -395,8 +398,8 @@ func TestRegisterTopic_HandlesPanic(t *testing.T) {
if err != nil {
t.Fatalf("Failed to create new server: %v", err)
}
topic := "test_topic"
testMessage := &testpb.TestMessage{Foo: "bar"}
topic := testTopic
testMessage := &testpb.TestMessage{Foo: bar}
var panicAdapter Adapter = func(next Handler) Handler {
return func(msg Message) {

View File

@@ -4,6 +4,7 @@ package params
import (
"math/big"
"time"
)
// BeaconChainConfig contains constant configs for node to participate in beacon chain.
@@ -105,18 +106,21 @@ type BeaconChainConfig struct {
DomainTransfer uint64 // DomainTransfer defines the BLS signature domain for transfer verification.
// Prysm constants.
GweiPerEth uint64 // GweiPerEth is the amount of gwei corresponding to 1 eth.
DepositsForChainStart uint64 // DepositsForChainStart defines how many validator deposits needed to kick off beacon chain.
RandBytes uint64 // RandBytes is the number of bytes used as entropy to shuffle validators.
BatchBlockLimit uint64 // BatchBlockLimit is maximum number of blocks that can be requested for initial sync.
SyncEpochLimit uint64 // SyncEpochLimit is the number of epochs the current node can be behind before it requests for the latest state.
MaxNumLog2Validators uint64 // MaxNumLog2Validators is the Max number of validators in Log2 exists given total ETH supply.
SyncPollingInterval int64 // SyncPollingInterval queries network nodes for sync status.
LogBlockDelay int64 // Number of blocks to wait from the current head before processing logs from the deposit contract.
BLSPubkeyLength int // BLSPubkeyLength defines the expected length of BLS public keys in bytes.
DefaultBufferSize int // DefaultBufferSize for channels across the Prysm repository.
ValidatorPrivkeyFileName string // ValidatorPrivKeyFileName specifies the string name of a validator private key file.
WithdrawalPrivkeyFileName string // WithdrawalPrivKeyFileName specifies the string name of a withdrawal private key file.
GweiPerEth uint64 // GweiPerEth is the amount of gwei corresponding to 1 eth.
DepositsForChainStart uint64 // DepositsForChainStart defines how many validator deposits needed to kick off beacon chain.
RandBytes uint64 // RandBytes is the number of bytes used as entropy to shuffle validators.
BatchBlockLimit uint64 // BatchBlockLimit is maximum number of blocks that can be requested for initial sync.
SyncEpochLimit uint64 // SyncEpochLimit is the number of epochs the current node can be behind before it requests for the latest state.
MaxNumLog2Validators uint64 // MaxNumLog2Validators is the Max number of validators in Log2 exists given total ETH supply.
SyncPollingInterval int64 // SyncPollingInterval queries network nodes for sync status.
LogBlockDelay int64 // Number of blocks to wait from the current head before processing logs from the deposit contract.
BLSPubkeyLength int // BLSPubkeyLength defines the expected length of BLS public keys in bytes.
DefaultBufferSize int // DefaultBufferSize for channels across the Prysm repository.
ValidatorPrivkeyFileName string // ValidatorPrivKeyFileName specifies the string name of a validator private key file.
WithdrawalPrivkeyFileName string // WithdrawalPrivKeyFileName specifies the string name of a withdrawal private key file.
HashCacheSize int64 // HashCacheSize defines the size of object hashes that are cached.
RPCSyncCheck time.Duration // Number of seconds to query the sync service, to find out if the node is synced or not.
TestnetContractEndpoint string // TestnetContractEndpoint to fetch the contract address of the Prysmatic Labs testnet.
}
// DepositContractConfig contains the deposits for
@@ -228,8 +232,13 @@ var defaultBeaconConfig = &BeaconChainConfig{
LogBlockDelay: 2,
BLSPubkeyLength: 96,
DefaultBufferSize: 10000,
HashCacheSize: 100000,
WithdrawalPrivkeyFileName: "/shardwithdrawalkey",
ValidatorPrivkeyFileName: "/validatorprivatekey",
RPCSyncCheck: 1,
// Testnet misc values.
TestnetContractEndpoint: "https://beta.prylabs.net/contract", // defines an http endpoint to fetch the testnet contract addr.
}
var defaultShardConfig = &ShardChainConfig{

View File

@@ -18,12 +18,8 @@ go_test(
"slice_test.go",
],
embed = [":go_default_library"],
deps = ["//shared/ssz:go_default_library"],
)
go_test(
name = "go_generic_test",
srcs = ["slice_generic_test.go"],
embed = [":go_default_library"],
deps = ["//shared/ssz:go_default_library"],
deps = [
"//shared/featureconfig:go_default_library",
"//shared/ssz:go_default_library",
],
)

View File

@@ -1,73 +1,5 @@
package sliceutil
// Intersection of two uint64 slices with time
// complexity of approximately O(n) leveraging a map to
// check for element existence off by a constant factor
// of underlying map efficiency.
func Intersection(a []uint64, b []uint64) []uint64 {
set := make([]uint64, 0)
m := make(map[uint64]bool)
for i := 0; i < len(a); i++ {
m[a[i]] = true
}
for i := 0; i < len(b); i++ {
if _, found := m[b[i]]; found {
set = append(set, b[i])
}
}
return set
}
// Union of two uint64 slices with time
// complexity of approximately O(n) leveraging a map to
// check for element existence off by a constant factor
// of underlying map efficiency.
func Union(a []uint64, b []uint64) []uint64 {
set := make([]uint64, 0)
m := make(map[uint64]bool)
for i := 0; i < len(a); i++ {
m[a[i]] = true
set = append(set, a[i])
}
for i := 0; i < len(b); i++ {
if _, found := m[b[i]]; !found {
set = append(set, b[i])
}
}
return set
}
// Not returns the uint64 in slice a that are
// not in slice b with time complexity of approximately
// O(n) leveraging a map to check for element existence
// off by a constant factor of underlying map efficiency.
func Not(a []uint64, b []uint64) []uint64 {
set := make([]uint64, 0)
m := make(map[uint64]bool)
for i := 0; i < len(a); i++ {
m[a[i]] = true
}
for i := 0; i < len(b); i++ {
if _, found := m[b[i]]; !found {
set = append(set, b[i])
}
}
return set
}
// IsIn returns true if a is in b and False otherwise.
func IsIn(a uint64, b []uint64) bool {
for _, v := range b {
if a == v {
return true
}
}
return false
}
// IntersectionUint64 of two uint64 slices with time
// complexity of approximately O(n) leveraging a map to
// check for element existence off by a constant factor
@@ -136,74 +68,6 @@ func IsInUint64(a uint64, b []uint64) bool {
return false
}
// Intersectionint64 of two int64 slices with time
// complexity of approximately O(n) leveraging a map to
// check for element existence off by a constant factor
// of underlying map efficiency.
func Intersectionint64(a []int64, b []int64) []int64 {
set := make([]int64, 0)
m := make(map[int64]bool)
for i := 0; i < len(a); i++ {
m[a[i]] = true
}
for i := 0; i < len(b); i++ {
if _, found := m[b[i]]; found {
set = append(set, b[i])
}
}
return set
}
// Unionint64 of two int64 slices with time
// complexity of approximately O(n) leveraging a map to
// check for element existence off by a constant factor
// of underlying map efficiency.
func Unionint64(a []int64, b []int64) []int64 {
set := make([]int64, 0)
m := make(map[int64]bool)
for i := 0; i < len(a); i++ {
m[a[i]] = true
set = append(set, a[i])
}
for i := 0; i < len(b); i++ {
if _, found := m[b[i]]; !found {
set = append(set, b[i])
}
}
return set
}
// Notint64 returns the int64 in slice a that are
// not in slice b with time complexity of approximately
// O(n) leveraging a map to check for element existence
// off by a constant factor of underlying map efficiency.
func Notint64(a []int64, b []int64) []int64 {
set := make([]int64, 0)
m := make(map[int64]bool)
for i := 0; i < len(a); i++ {
m[a[i]] = true
}
for i := 0; i < len(b); i++ {
if _, found := m[b[i]]; !found {
set = append(set, b[i])
}
}
return set
}
// IsInint64 returns true if a is in b and False otherwise.
func IsInint64(a int64, b []int64) bool {
for _, v := range b {
if a == v {
return true
}
}
return false
}
// IntersectionInt64 of two int64 slices with time
// complexity of approximately O(n) leveraging a map to
// check for element existence off by a constant factor

View File

@@ -5,9 +5,16 @@ import (
"reflect"
"testing"
"github.com/prysmaticlabs/prysm/shared/featureconfig"
"github.com/prysmaticlabs/prysm/shared/ssz"
)
func init() {
featureconfig.InitFeatureConfig(&featureconfig.FeatureFlagConfig{
CacheTreeHash: false,
})
}
func TestGenericIntersection(t *testing.T) {
testCases := []struct {
setA []uint64
@@ -363,7 +370,7 @@ func BenchmarkIntersection(b *testing.B) {
{[]uint64{1}, []uint64{1}, []uint64{1}},
}
for _, tt := range testCases {
Intersection(tt.setA, tt.setB)
IntersectionUint64(tt.setA, tt.setB)
}
}
@@ -386,7 +393,7 @@ func BenchmarkUnion(b *testing.B) {
{[]uint64{1}, []uint64{1}, []uint64{1}},
}
for _, tt := range testCases {
Union(tt.setA, tt.setB)
UnionUint64(tt.setA, tt.setB)
}
@@ -436,7 +443,7 @@ func BenchmarkNot(b *testing.B) {
{[]uint64{1}, []uint64{1}, []uint64{1}},
}
for _, tt := range testCases {
Not(tt.setA, tt.setB)
NotUint64(tt.setA, tt.setB)
}
@@ -483,7 +490,7 @@ func BenchmarkIsIn(b *testing.B) {
{100, []uint64{2, 3, 5, 4, 6}, false},
}
for _, tt := range testCases {
IsIn(tt.a, tt.b)
IsInUint64(tt.a, tt.b)
}

View File

@@ -5,93 +5,6 @@ import (
"testing"
)
func TestIntersection(t *testing.T) {
testCases := []struct {
setA []uint64
setB []uint64
out []uint64
}{
{[]uint64{2, 3, 5}, []uint64{3}, []uint64{3}},
{[]uint64{2, 3, 5}, []uint64{3, 5}, []uint64{3, 5}},
{[]uint64{2, 3, 5}, []uint64{5, 3, 2}, []uint64{5, 3, 2}},
{[]uint64{2, 3, 5}, []uint64{2, 3, 5}, []uint64{2, 3, 5}},
{[]uint64{2, 3, 5}, []uint64{}, []uint64{}},
{[]uint64{}, []uint64{2, 3, 5}, []uint64{}},
{[]uint64{}, []uint64{}, []uint64{}},
{[]uint64{1}, []uint64{1}, []uint64{1}},
}
for _, tt := range testCases {
result := Intersection(tt.setA, tt.setB)
if !reflect.DeepEqual(result, tt.out) {
t.Errorf("got %d, want %d", result, tt.out)
}
}
}
func TestUnion(t *testing.T) {
testCases := []struct {
setA []uint64
setB []uint64
out []uint64
}{
{[]uint64{2, 3, 5}, []uint64{4, 6}, []uint64{2, 3, 5, 4, 6}},
{[]uint64{2, 3, 5}, []uint64{3, 5}, []uint64{2, 3, 5}},
{[]uint64{2, 3, 5}, []uint64{2, 3, 5}, []uint64{2, 3, 5}},
{[]uint64{2, 3, 5}, []uint64{}, []uint64{2, 3, 5}},
{[]uint64{}, []uint64{2, 3, 5}, []uint64{2, 3, 5}},
{[]uint64{}, []uint64{}, []uint64{}},
{[]uint64{1}, []uint64{1}, []uint64{1}},
}
for _, tt := range testCases {
result := Union(tt.setA, tt.setB)
if !reflect.DeepEqual(result, tt.out) {
t.Errorf("got %d, want %d", result, tt.out)
}
}
}
func TestNot(t *testing.T) {
testCases := []struct {
setA []uint64
setB []uint64
out []uint64
}{
{[]uint64{4, 6}, []uint64{2, 3, 5, 4, 6}, []uint64{2, 3, 5}},
{[]uint64{3, 5}, []uint64{2, 3, 5}, []uint64{2}},
{[]uint64{2, 3, 5}, []uint64{2, 3, 5}, []uint64{}},
{[]uint64{2}, []uint64{2, 3, 5}, []uint64{3, 5}},
{[]uint64{}, []uint64{2, 3, 5}, []uint64{2, 3, 5}},
{[]uint64{}, []uint64{}, []uint64{}},
{[]uint64{1}, []uint64{1}, []uint64{}},
}
for _, tt := range testCases {
result := Not(tt.setA, tt.setB)
if !reflect.DeepEqual(result, tt.out) {
t.Errorf("got %d, want %d", result, tt.out)
}
}
}
func TestIsIn(t *testing.T) {
testCases := []struct {
a uint64
b []uint64
result bool
}{
{0, []uint64{}, false},
{0, []uint64{0}, true},
{4, []uint64{2, 3, 5, 4, 6}, true},
{100, []uint64{2, 3, 5, 4, 6}, false},
}
for _, tt := range testCases {
result := IsIn(tt.a, tt.b)
if result != tt.result {
t.Errorf("IsIn(%d, %v)=%v, wanted: %v",
tt.a, tt.b, result, tt.result)
}
}
}
func TestIntersectionUint64(t *testing.T) {
testCases := []struct {
setA []uint64
@@ -116,31 +29,6 @@ func TestIntersectionUint64(t *testing.T) {
}
}
func TestIntersectionint64(t *testing.T) {
testCases := []struct {
setA []int64
setB []int64
out []int64
}{
{[]int64{2, 3, 5}, []int64{3}, []int64{3}},
{[]int64{2, 3, 5}, []int64{3, 5}, []int64{3, 5}},
{[]int64{2, 3, 5}, []int64{5, 3, 2}, []int64{5, 3, 2}},
{[]int64{2, 3, 5}, []int64{2, 3, 5}, []int64{2, 3, 5}},
{[]int64{2, 3, 5}, []int64{}, []int64{}},
{[]int64{}, []int64{2, 3, 5}, []int64{}},
{[]int64{}, []int64{}, []int64{}},
{[]int64{1}, []int64{1}, []int64{1}},
}
for _, tt := range testCases {
result := Intersectionint64(tt.setA, tt.setB)
if !reflect.DeepEqual(result, tt.out) {
t.Errorf("got %d, want %d", result, tt.out)
}
}
}
func TestIntersectionInt64(t *testing.T) {
testCases := []struct {
setA []int64
@@ -189,30 +77,6 @@ func TestUnionUint64(t *testing.T) {
}
}
func TestUnionint64(t *testing.T) {
testCases := []struct {
setA []int64
setB []int64
out []int64
}{
{[]int64{2, 3, 5}, []int64{4, 6}, []int64{2, 3, 5, 4, 6}},
{[]int64{2, 3, 5}, []int64{3, 5}, []int64{2, 3, 5}},
{[]int64{2, 3, 5}, []int64{2, 3, 5}, []int64{2, 3, 5}},
{[]int64{2, 3, 5}, []int64{}, []int64{2, 3, 5}},
{[]int64{}, []int64{2, 3, 5}, []int64{2, 3, 5}},
{[]int64{}, []int64{}, []int64{}},
{[]int64{1}, []int64{1}, []int64{1}},
}
for _, tt := range testCases {
result := Unionint64(tt.setA, tt.setB)
if !reflect.DeepEqual(result, tt.out) {
t.Errorf("got %d, want %d", result, tt.out)
}
}
}
func TestUnionInt64(t *testing.T) {
testCases := []struct {
setA []int64
@@ -234,6 +98,7 @@ func TestUnionInt64(t *testing.T) {
}
}
}
func TestNotUint64(t *testing.T) {
@@ -280,28 +145,6 @@ func TestNotInt64(t *testing.T) {
}
}
func TestNotint64(t *testing.T) {
testCases := []struct {
setA []int64
setB []int64
out []int64
}{
{[]int64{4, 6}, []int64{2, 3, 5, 4, 6}, []int64{2, 3, 5}},
{[]int64{3, 5}, []int64{2, 3, 5}, []int64{2}},
{[]int64{2, 3, 5}, []int64{2, 3, 5}, []int64{}},
{[]int64{2}, []int64{2, 3, 5}, []int64{3, 5}},
{[]int64{}, []int64{2, 3, 5}, []int64{2, 3, 5}},
{[]int64{}, []int64{}, []int64{}},
{[]int64{1}, []int64{1}, []int64{}},
}
for _, tt := range testCases {
result := Notint64(tt.setA, tt.setB)
if !reflect.DeepEqual(result, tt.out) {
t.Errorf("got %d, want %d", result, tt.out)
}
}
}
func TestIsInUint64(t *testing.T) {
testCases := []struct {
a uint64
@@ -322,26 +165,6 @@ func TestIsInUint64(t *testing.T) {
}
}
func TestIsInint64(t *testing.T) {
testCases := []struct {
a int64
b []int64
result bool
}{
{0, []int64{}, false},
{0, []int64{0}, true},
{4, []int64{2, 3, 5, 4, 6}, true},
{100, []int64{2, 3, 5, 4, 6}, false},
}
for _, tt := range testCases {
result := IsInint64(tt.a, tt.b)
if result != tt.result {
t.Errorf("IsIn(%d, %v)=%v, wanted: %v",
tt.a, tt.b, result, tt.result)
}
}
}
func TestIsInInt64(t *testing.T) {
testCases := []struct {
a int64

View File

@@ -7,13 +7,20 @@ go_library(
"doc.go",
"encode.go",
"hash.go",
"hash_cache.go",
"ssz_utils_cache.go",
],
importpath = "github.com/prysmaticlabs/prysm/shared/ssz",
visibility = ["//visibility:public"],
deps = [
"//shared/bytesutil:go_default_library",
"//shared/featureconfig:go_default_library",
"//shared/hashutil:go_default_library",
"//shared/params:go_default_library",
"@com_github_ethereum_go_ethereum//common:go_default_library",
"@com_github_karlseguin_ccache//:go_default_library",
"@com_github_prometheus_client_golang//prometheus:go_default_library",
"@com_github_prometheus_client_golang//prometheus/promauto:go_default_library",
],
)
@@ -24,7 +31,12 @@ go_test(
"encode_test.go",
"example_and_test.go",
"example_encode_test.go",
"hash_cache_test.go",
"hash_test.go",
],
embed = [":go_default_library"],
deps = [
"//shared/bytesutil:go_default_library",
"//shared/featureconfig:go_default_library",
],
)

View File

@@ -6,6 +6,8 @@ import (
"fmt"
"reflect"
"testing"
"github.com/prysmaticlabs/prysm/shared/featureconfig"
)
type decodeTest struct {
@@ -184,6 +186,12 @@ var decodeTests = []decodeTest{
{input: "04000000 0200 01 01", ptr: new(simpleStruct), error: "decode error: input is too long for output type ssz.simpleStruct"},
}
func init() {
featureconfig.InitFeatureConfig(&featureconfig.FeatureFlagConfig{
CacheTreeHash: false,
})
}
func runTests(t *testing.T, decode func([]byte, interface{}) error) {
for i, test := range decodeTests {
input, err := hex.DecodeString(stripSpace(test.input))

View File

@@ -7,12 +7,15 @@ import (
"reflect"
"github.com/prysmaticlabs/prysm/shared/bytesutil"
"github.com/prysmaticlabs/prysm/shared/featureconfig"
"github.com/prysmaticlabs/prysm/shared/hashutil"
)
const hashLengthBytes = 32
const sszChunkSize = 128
var useCache bool
// Hashable defines the interface for supporting tree-hash function.
type Hashable interface {
TreeHashSSZ() ([32]byte, error)
@@ -51,6 +54,7 @@ func newHashError(msg string, typ reflect.Type) *hashError {
}
func makeHasher(typ reflect.Type) (hasher, error) {
useCache = featureconfig.FeatureConfig().CacheTreeHash
kind := typ.Kind()
switch {
case kind == reflect.Bool ||
@@ -64,8 +68,14 @@ func makeHasher(typ reflect.Type) (hasher, error) {
kind == reflect.Array && typ.Elem().Kind() == reflect.Uint8:
return hashedEncoding, nil
case kind == reflect.Slice || kind == reflect.Array:
if useCache {
return makeSliceHasherCache(typ)
}
return makeSliceHasher(typ)
case kind == reflect.Struct:
if useCache {
return makeStructHasherCache(typ)
}
return makeStructHasher(typ)
case kind == reflect.Ptr:
return makePtrHasher(typ)

234
shared/ssz/hash_cache.go Normal file
View File

@@ -0,0 +1,234 @@
package ssz
import (
"errors"
"fmt"
"reflect"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/karlseguin/ccache"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
"github.com/prysmaticlabs/prysm/shared/bytesutil"
"github.com/prysmaticlabs/prysm/shared/hashutil"
"github.com/prysmaticlabs/prysm/shared/params"
)
var (
// ErrNotMerkleRoot will be returned when a cache object is not a merkle root.
ErrNotMerkleRoot = errors.New("object is not a merkle root")
// maxCacheSize is 2x of the follow distance for additional cache padding.
// Requests should be only accessing blocks within recent blocks within the
// Eth1FollowDistance.
maxCacheSize = params.BeaconConfig().HashCacheSize
// Metrics
hashCacheMiss = promauto.NewCounter(prometheus.CounterOpts{
Name: "hash_cache_miss",
Help: "The number of hash requests that aren't present in the cache.",
})
hashCacheHit = promauto.NewCounter(prometheus.CounterOpts{
Name: "hash_cache_hit",
Help: "The number of hash requests that are present in the cache.",
})
hashCacheSize = promauto.NewGauge(prometheus.GaugeOpts{
Name: "hash_cache_size",
Help: "The number of hashes in the block cache",
})
)
// hashCacheS struct with one queue for looking up by hash.
type hashCacheS struct {
hashCache *ccache.Cache
}
// root specifies the hash of data in a struct
type root struct {
Hash common.Hash
MerkleRoot []byte
}
// newHashCache creates a new hash cache for storing/accessing root hashes from
// memory.
func newHashCache() *hashCacheS {
return &hashCacheS{
hashCache: ccache.New(ccache.Configure().MaxSize(maxCacheSize)),
}
}
// RootByEncodedHash fetches Root by the encoded hash of the object. Returns true with a
// reference to the root if exists. Otherwise returns false, nil.
func (b *hashCacheS) RootByEncodedHash(h common.Hash) (bool, *root, error) {
item := b.hashCache.Get(h.Hex())
if item == nil {
hashCacheMiss.Inc()
return false, nil, nil
}
hashCacheHit.Inc()
hInfo, ok := item.Value().(*root)
if !ok {
return false, nil, ErrNotMerkleRoot
}
return true, hInfo, nil
}
// TrieRootCached computes a trie root and add it to the cache.
// if the encoded hash of the object is in cache, it will be retrieved from cache.
// This method also trims the least recently added root info. if the cache size
// has reached the max cache size limit.
func (b *hashCacheS) TrieRootCached(val interface{}) ([32]byte, error) {
if val == nil {
return [32]byte{}, newHashError("untyped nil is not supported", nil)
}
rval := reflect.ValueOf(val)
hs, err := hashedEncoding(rval)
if err != nil {
return [32]byte{}, newHashError(fmt.Sprint(err), rval.Type())
}
exists, fetchedInfo, err := b.RootByEncodedHash(bytesutil.ToBytes32(hs))
if err != nil {
return [32]byte{}, newHashError(fmt.Sprint(err), rval.Type())
}
var paddedOutput [32]byte
if exists {
paddedOutput = bytesutil.ToBytes32(fetchedInfo.MerkleRoot)
} else {
sszUtils, err := cachedSSZUtils(rval.Type())
if err != nil {
return [32]byte{}, newHashError(fmt.Sprint(err), rval.Type())
}
output, err := sszUtils.hasher(rval)
if err != nil {
return [32]byte{}, newHashError(fmt.Sprint(err), rval.Type())
}
// Right-pad with 0 to make 32 bytes long, if necessary.
paddedOutput = bytesutil.ToBytes32(output)
err = b.AddRoot(bytesutil.ToBytes32(hs), paddedOutput[:])
if err != nil {
return [32]byte{}, newHashError(fmt.Sprint(err), rval.Type())
}
}
return paddedOutput, nil
}
// MerkleHashCached adds a merkle object to the cache. This method also trims the
// least recently added root info if the cache size has reached the max cache
// size limit.
func (b *hashCacheS) MerkleHashCached(byteSlice [][]byte) ([]byte, error) {
mh := []byte{}
hs, err := hashedEncoding(reflect.ValueOf(byteSlice))
if err != nil {
return mh, newHashError(fmt.Sprint(err), reflect.TypeOf(byteSlice))
}
exists, fetchedInfo, err := b.RootByEncodedHash(bytesutil.ToBytes32(hs))
if err != nil {
return mh, newHashError(fmt.Sprint(err), reflect.TypeOf(byteSlice))
}
if exists {
mh = fetchedInfo.MerkleRoot
} else {
mh, err = merkleHash(byteSlice)
if err != nil {
return nil, err
}
mr := &root{
Hash: bytesutil.ToBytes32(hs),
MerkleRoot: mh,
}
b.hashCache.Set(mr.Hash.Hex(), mr, time.Hour)
hashCacheSize.Set(float64(b.hashCache.ItemCount()))
}
return mh, nil
}
// AddRoot adds an encodedhash of the object as key and a rootHash object to the cache.
// This method also trims the
// least recently added root info if the cache size has reached the max cache
// size limit.
func (b *hashCacheS) AddRoot(h common.Hash, rootB []byte) error {
mr := &root{
Hash: h,
MerkleRoot: rootB,
}
b.hashCache.Set(mr.Hash.Hex(), mr, time.Hour)
return nil
}
// MakeSliceHasherCache add caching mechanism to slice hasher.
func makeSliceHasherCache(typ reflect.Type) (hasher, error) {
elemSSZUtils, err := cachedSSZUtilsNoAcquireLock(typ.Elem())
if err != nil {
return nil, fmt.Errorf("failed to get ssz utils: %v", err)
}
hasher := func(val reflect.Value) ([]byte, error) {
hs, err := hashedEncoding(val)
if err != nil {
return nil, fmt.Errorf("failed to encode element of slice/array: %v", err)
}
exists, fetchedInfo, err := hashCache.RootByEncodedHash(bytesutil.ToBytes32(hs))
if err != nil {
return nil, fmt.Errorf("failed to encode element of slice/array: %v", err)
}
var output []byte
if exists {
output = fetchedInfo.MerkleRoot
} else {
var elemHashList [][]byte
for i := 0; i < val.Len(); i++ {
elemHash, err := elemSSZUtils.hasher(val.Index(i))
if err != nil {
return nil, fmt.Errorf("failed to hash element of slice/array: %v", err)
}
elemHashList = append(elemHashList, elemHash)
}
output, err = hashCache.MerkleHashCached(elemHashList)
if err != nil {
return nil, fmt.Errorf("failed to calculate merkle hash of element hash list: %v", err)
}
err := hashCache.AddRoot(bytesutil.ToBytes32(hs), output)
if err != nil {
return nil, fmt.Errorf("failed to add root to cache: %v", err)
}
hashCacheSize.Set(float64(hashCache.hashCache.ItemCount()))
}
return output, nil
}
return hasher, nil
}
func makeStructHasherCache(typ reflect.Type) (hasher, error) {
fields, err := structFields(typ)
if err != nil {
return nil, err
}
hasher := func(val reflect.Value) ([]byte, error) {
hs, err := hashedEncoding(val)
if err != nil {
return nil, fmt.Errorf("failed to encode element of slice/array: %v", err)
}
exists, fetchedInfo, err := hashCache.RootByEncodedHash(bytesutil.ToBytes32(hs))
if err != nil {
return nil, fmt.Errorf("failed to encode element of slice/array: %v", err)
}
var result [32]byte
if exists {
result = bytesutil.ToBytes32(fetchedInfo.MerkleRoot)
return result[:], nil
}
concatElemHash := make([]byte, 0)
for _, f := range fields {
elemHash, err := f.sszUtils.hasher(val.Field(f.index))
if err != nil {
return nil, fmt.Errorf("failed to hash field of struct: %v", err)
}
concatElemHash = append(concatElemHash, elemHash...)
}
result = hashutil.Hash(concatElemHash)
return result[:], nil
}
return hasher, nil
}

View File

@@ -0,0 +1,148 @@
package ssz
import (
"bytes"
"log"
"reflect"
"testing"
"time"
"github.com/prysmaticlabs/prysm/shared/bytesutil"
"github.com/prysmaticlabs/prysm/shared/featureconfig"
)
type junkObject struct {
D2Int64Slice [][]uint64
Uint uint64
Int64Slice []uint64
}
type tree struct {
First []*junkObject
Second []*junkObject
}
func generateJunkObject(size uint64) []*junkObject {
object := make([]*junkObject, size)
for i := uint64(0); i < uint64(len(object)); i++ {
d2Int64Slice := make([][]uint64, size)
is := make([]uint64, size)
uInt := uint64(time.Now().UnixNano())
is[i] = i
d2Int64Slice[i] = make([]uint64, size)
for j := uint64(0); j < uint64(len(object)); j++ {
d2Int64Slice[i][j] = i + j
}
object[i] = &junkObject{
D2Int64Slice: d2Int64Slice,
Uint: uInt,
Int64Slice: is,
}
}
return object
}
func TestObjCache_byHash(t *testing.T) {
cache := newHashCache()
byteSl := [][]byte{{0, 0}, {1, 1}}
mr, err := merkleHash(byteSl)
if err != nil {
t.Fatal(err)
}
hs, err := hashedEncoding(reflect.ValueOf(byteSl))
if err != nil {
t.Fatal(err)
}
exists, _, err := cache.RootByEncodedHash(bytesutil.ToBytes32(hs))
if err != nil {
t.Fatal(err)
}
if exists {
t.Error("Expected block info not to exist in empty cache")
}
if _, err := cache.MerkleHashCached(byteSl); err != nil {
t.Fatal(err)
}
exists, fetchedInfo, err := cache.RootByEncodedHash(bytesutil.ToBytes32(hs))
if err != nil {
t.Fatal(err)
}
if !exists {
t.Error("Expected blockInfo to exist")
}
if !bytes.Equal(mr, fetchedInfo.MerkleRoot) {
t.Errorf(
"Expected fetched info number to be %v, got %v",
mr,
fetchedInfo.MerkleRoot,
)
}
if fetchedInfo.Hash != bytesutil.ToBytes32(hs) {
t.Errorf(
"Expected fetched info hash to be %v, got %v",
hs,
fetchedInfo.Hash,
)
}
}
func TestMerkleHashWithCache(t *testing.T) {
cache := newHashCache()
for i := 0; i < 200; i++ {
runMerkleHashTests(t, func(val [][]byte) ([]byte, error) {
return merkleHash(val)
})
}
for i := 0; i < 200; i++ {
runMerkleHashTests(t, func(val [][]byte) ([]byte, error) {
return cache.MerkleHashCached(val)
})
}
}
func BenchmarkHashWithoutCache(b *testing.B) {
featureconfig.FeatureConfig().CacheTreeHash = false
First := generateJunkObject(100)
TreeHash(&tree{First: First, Second: First})
for n := 0; n < b.N; n++ {
TreeHash(&tree{First: First, Second: First})
}
}
func BenchmarkHashWithCache(b *testing.B) {
featureconfig.FeatureConfig().CacheTreeHash = true
First := generateJunkObject(100)
type tree struct {
First []*junkObject
Second []*junkObject
}
TreeHash(&tree{First: First, Second: First})
for n := 0; n < b.N; n++ {
TreeHash(&tree{First: First, Second: First})
}
}
func TestBlockCache_maxSize(t *testing.T) {
maxCacheSize = 10000
cache := newHashCache()
for i := uint64(0); i < uint64(maxCacheSize+1025); i++ {
if err := cache.AddRoot(bytesutil.ToBytes32(bytesutil.Bytes4(i)), []byte{1}); err != nil {
t.Fatal(err)
}
}
log.Printf(
"hash cache key size is %d, itemcount is %d",
maxCacheSize,
cache.hashCache.ItemCount(),
)
time.Sleep(1 * time.Second)
if int64(cache.hashCache.ItemCount()) > maxCacheSize {
t.Errorf(
"Expected hash cache key size to be %d, got %d",
maxCacheSize,
cache.hashCache.ItemCount(),
)
}
}

View File

@@ -29,6 +29,7 @@ type sszUtils struct {
var (
sszUtilsCacheMutex sync.RWMutex
sszUtilsCache = make(map[reflect.Type]*sszUtils)
hashCache = newHashCache()
)
// Get cached encoder, encodeSizer and decoder implementation for a specified type.

View File

@@ -7,7 +7,7 @@ go_library(
visibility = ["//visibility:public"],
deps = [
"@com_github_sirupsen_logrus//:go_default_library",
"@io_opencensus_go//exporter/jaeger:go_default_library",
"@io_opencensus_go//trace:go_default_library",
"@io_opencensus_go_contrib_exporter_jaeger//:go_default_library",
],
)

View File

@@ -3,8 +3,8 @@ package tracing
import (
"errors"
"contrib.go.opencensus.io/exporter/jaeger"
"github.com/sirupsen/logrus"
"go.opencensus.io/exporter/jaeger"
"go.opencensus.io/trace"
)

View File

@@ -21,6 +21,7 @@ go_library(
"@com_github_sirupsen_logrus//:go_default_library",
"@com_github_urfave_cli//:go_default_library",
"@com_github_x_cray_logrus_prefixed_formatter//:go_default_library",
"@org_golang_x_crypto//ssh/terminal:go_default_library",
],
)
@@ -49,6 +50,7 @@ go_image(
"@com_github_sirupsen_logrus//:go_default_library",
"@com_github_urfave_cli//:go_default_library",
"@com_github_x_cray_logrus_prefixed_formatter//:go_default_library",
"@org_golang_x_crypto//ssh/terminal:go_default_library",
],
)

View File

@@ -18,6 +18,7 @@ go_test(
srcs = ["account_test.go"],
embed = [":go_default_library"],
deps = [
"//shared/featureconfig:go_default_library",
"//shared/keystore:go_default_library",
"//shared/params:go_default_library",
"//shared/testutil:go_default_library",

View File

@@ -6,6 +6,8 @@ import (
"encoding/hex"
"errors"
"fmt"
"io"
"os"
"github.com/prysmaticlabs/prysm/shared/keystore"
"github.com/prysmaticlabs/prysm/shared/params"
@@ -87,3 +89,23 @@ func NewValidatorAccount(directory string, password string) error {
`, serializedData)
return nil
}
// Exists checks if a validator account at a given keystore path exists.
func Exists(keystorePath string) (bool, error) {
/* #nosec */
f, err := os.Open(keystorePath)
if err != nil {
return false, nil
}
defer func() {
if err := f.Close(); err != nil {
log.Fatal(err)
}
}()
_, err = f.Readdirnames(1) // Or f.Readdir(1)
if err == io.EOF {
return false, nil
}
return true, err
}

View File

@@ -6,11 +6,18 @@ import (
"os"
"testing"
"github.com/prysmaticlabs/prysm/shared/featureconfig"
"github.com/prysmaticlabs/prysm/shared/keystore"
"github.com/prysmaticlabs/prysm/shared/params"
"github.com/prysmaticlabs/prysm/shared/testutil"
)
func init() {
featureconfig.InitFeatureConfig(&featureconfig.FeatureFlagConfig{
CacheTreeHash: false,
})
}
func TestNewValidatorAccount_AccountExists(t *testing.T) {
directory := testutil.TempDir() + "/testkeystore"
defer os.RemoveAll(directory)

View File

@@ -51,6 +51,7 @@ go_test(
"//proto/beacon/rpc/v1:go_default_library",
"//shared:go_default_library",
"//shared/bitutil:go_default_library",
"//shared/featureconfig:go_default_library",
"//shared/keystore:go_default_library",
"//shared/mathutil:go_default_library",
"//shared/params:go_default_library",

View File

@@ -28,7 +28,7 @@ type Validator interface {
}
// Run the main validator routine. This routine exits if the context is
// cancelled.
// canceled.
//
// Order of operations:
// 1 - Initialize validator data

View File

@@ -10,6 +10,7 @@ import (
"time"
"github.com/prysmaticlabs/prysm/shared"
"github.com/prysmaticlabs/prysm/shared/featureconfig"
"github.com/prysmaticlabs/prysm/shared/keystore"
"github.com/prysmaticlabs/prysm/shared/testutil"
"github.com/prysmaticlabs/prysm/validator/accounts"
@@ -34,6 +35,12 @@ func keySetup() {
}
}
func init() {
featureconfig.InitFeatureConfig(&featureconfig.FeatureFlagConfig{
CacheTreeHash: false,
})
}
func TestMain(m *testing.M) {
dir := testutil.TempDir() + "/keystore1"
defer os.RemoveAll(dir)
@@ -62,7 +69,7 @@ func TestStop_CancelsContext(t *testing.T) {
func TestLifecycle(t *testing.T) {
hook := logTest.NewGlobal()
// Use cancelled context so that the run function exits immediately..
// Use canceled context so that the run function exits immediately..
ctx, cancel := context.WithCancel(context.Background())
cancel()
validatorService := &ValidatorService{
@@ -81,7 +88,7 @@ func TestLifecycle(t *testing.T) {
func TestLifecycle_Insecure(t *testing.T) {
hook := logTest.NewGlobal()
// Use cancelled context so that the run function exits immediately.
// Use canceled context so that the run function exits immediately.
ctx, cancel := context.WithCancel(context.Background())
cancel()
validatorService := &ValidatorService{

View File

@@ -67,7 +67,7 @@ func (v *validator) WaitForChainStart(ctx context.Context) error {
// Once the ChainStart log is received, we update the genesis time of the validator client
// and begin a slot ticker used to track the current slot the beacon node is in.
v.ticker = slotutil.GetSlotTicker(time.Unix(int64(v.genesisTime), 0), params.BeaconConfig().SecondsPerSlot)
log.Infof("Beacon chain initialized at unix time: %v", time.Unix(int64(v.genesisTime), 0))
log.WithField("genesisTime", time.Unix(int64(v.genesisTime), 0)).Info("Beacon chain initialized")
return nil
}

Some files were not shown because too many files have changed in this diff Show More