Feature/22 test handling incoming events #30
2
Makefile
2
Makefile
@ -66,7 +66,6 @@ unit-test-local:
|
|||||||
go vet ./...
|
go vet ./...
|
||||||
go fmt ./...
|
go fmt ./...
|
||||||
$(GINKGO) -r --label-filter unit \
|
$(GINKGO) -r --label-filter unit \
|
||||||
--procs=4 --compilers=4 \
|
|
||||||
--randomize-all --randomize-suites \
|
--randomize-all --randomize-suites \
|
||||||
--fail-on-pending --keep-going \
|
--fail-on-pending --keep-going \
|
||||||
--race --trace
|
--race --trace
|
||||||
@ -76,7 +75,6 @@ unit-test-ci:
|
|||||||
go vet ./...
|
go vet ./...
|
||||||
go fmt ./...
|
go fmt ./...
|
||||||
$(GINKGO) -r --label-filter unit \
|
$(GINKGO) -r --label-filter unit \
|
||||||
--procs=4 --compilers=4 \
|
|
||||||
--randomize-all --randomize-suites \
|
--randomize-all --randomize-suites \
|
||||||
--fail-on-pending --keep-going \
|
--fail-on-pending --keep-going \
|
||||||
--cover --coverprofile=cover.profile \
|
--cover --coverprofile=cover.profile \
|
||||||
|
13
README.md
13
README.md
@ -63,11 +63,24 @@ This project utilizes `ginkgo` for testing. A few notes on testing:
|
|||||||
|
|
||||||
### Testing the `pkg/beaconclient`
|
### Testing the `pkg/beaconclient`
|
||||||
|
|
||||||
|
To test the `pkg/beaconclient`, keep the following in mind.
|
||||||
|
|
||||||
|
#### Get SSZ Files
|
||||||
|
|
||||||
To test the `/pkg/beaconclient`, you will need to download data locally.
|
To test the `/pkg/beaconclient`, you will need to download data locally.
|
||||||
|
|
||||||
1. [Install Minio](https://docs.min.io/minio/baremetal/quickstart/quickstart.html), you only need the client, `mc`.
|
1. [Install Minio](https://docs.min.io/minio/baremetal/quickstart/quickstart.html), you only need the client, `mc`.
|
||||||
2. Run: `mc cp`
|
2. Run: `mc cp`
|
||||||
|
|
||||||
|
#### Understanding Testing Components
|
||||||
|
|
||||||
|
A few notes about the testing components.
|
||||||
|
|
||||||
|
- The `TestEvents` map contains several events for testers to leverage when testing.
|
||||||
|
- Any object ending in `-dummy` is not a real object. You will also notice it has a present field called `MimicConfig`. This object will use an existing SSZ object, and update the parameters from the `Head` and `MimicConfig`.
|
||||||
|
- This is done because creating an empty or minimal `SignedBeaconBlock` and `BeaconState` is fairly challenging.
|
||||||
|
- By slightly modifying an existing object, we can test re-org, malformed objects, and other negative conditions.
|
||||||
|
|
||||||
# Contribution
|
# Contribution
|
||||||
|
|
||||||
If you want to contribute please make sure you do the following:
|
If you want to contribute please make sure you do the following:
|
||||||
|
@ -21,12 +21,19 @@ var (
|
|||||||
//bcFinalizedTopicEndpoint = "/eth/v1/events?topics=finalized_checkpoint" // Endpoint used to subscribe to the head of the chain
|
//bcFinalizedTopicEndpoint = "/eth/v1/events?topics=finalized_checkpoint" // Endpoint used to subscribe to the head of the chain
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// A structure utilized for keeping track of various metrics.
|
||||||
|
type BeaconClientMetrics struct {
|
||||||
|
HeadTrackingInserts uint64
|
||||||
|
HeadTrackingReorgs uint64
|
||||||
|
}
|
||||||
|
|
||||||
// A struct that capture the Beacon Server that the Beacon Client will be interacting with and querying.
|
// A struct that capture the Beacon Server that the Beacon Client will be interacting with and querying.
|
||||||
type BeaconClient struct {
|
type BeaconClient struct {
|
||||||
Context context.Context // A context generic context with multiple uses.
|
Context context.Context // A context generic context with multiple uses.
|
||||||
ServerEndpoint string // What is the endpoint of the beacon server.
|
ServerEndpoint string // What is the endpoint of the beacon server.
|
||||||
PerformHistoricalProcessing bool // Should we perform historical processing?
|
PerformHistoricalProcessing bool // Should we perform historical processing?
|
||||||
Db sql.Database // Database object used for reads and writes.
|
Db sql.Database // Database object used for reads and writes.
|
||||||
|
Metrics *BeaconClientMetrics // An object used to keep track of certain BeaconClient Metrics.
|
||||||
|
|
||||||
// Used for Head Tracking
|
// Used for Head Tracking
|
||||||
PerformHeadTracking bool // Should we track head?
|
PerformHeadTracking bool // Should we track head?
|
||||||
@ -63,6 +70,10 @@ func CreateBeaconClient(ctx context.Context, connectionProtocol string, bcAddres
|
|||||||
ServerEndpoint: endpoint,
|
ServerEndpoint: endpoint,
|
||||||
HeadTracking: createSseEvent[Head](endpoint, BcHeadTopicEndpoint),
|
HeadTracking: createSseEvent[Head](endpoint, BcHeadTopicEndpoint),
|
||||||
ReOrgTracking: createSseEvent[ChainReorg](endpoint, bcReorgTopicEndpoint),
|
ReOrgTracking: createSseEvent[ChainReorg](endpoint, bcReorgTopicEndpoint),
|
||||||
|
Metrics: &BeaconClientMetrics{
|
||||||
|
HeadTrackingInserts: 0,
|
||||||
|
HeadTrackingReorgs: 0,
|
||||||
|
},
|
||||||
//FinalizationTracking: createSseEvent[FinalizedCheckpoint](endpoint, bcFinalizedTopicEndpoint),
|
//FinalizationTracking: createSseEvent[FinalizedCheckpoint](endpoint, bcFinalizedTopicEndpoint),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,17 +2,22 @@ package beaconclient_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jarcoal/httpmock"
|
"github.com/jarcoal/httpmock"
|
||||||
. "github.com/onsi/ginkgo/v2"
|
. "github.com/onsi/ginkgo/v2"
|
||||||
|
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
|
||||||
|
st "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||||
"github.com/r3labs/sse"
|
"github.com/r3labs/sse"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
|
|
||||||
@ -25,16 +30,20 @@ type Message struct {
|
|||||||
HeadMessage beaconclient.Head // The head messsage that will be streamed to the BeaconClient
|
HeadMessage beaconclient.Head // The head messsage that will be streamed to the BeaconClient
|
||||||
ReorgMessage beaconclient.ChainReorg // The reorg messsage that will be streamed to the BeaconClient
|
ReorgMessage beaconclient.ChainReorg // The reorg messsage that will be streamed to the BeaconClient
|
||||||
TestNotes string // A small explanation of the purpose this structure plays in the testing landscape.
|
TestNotes string // A small explanation of the purpose this structure plays in the testing landscape.
|
||||||
|
MimicConfig *MimicConfig // A configuration of parameters that you are trying to
|
||||||
SignedBeaconBlock string // The file path output of an SSZ encoded SignedBeaconBlock.
|
SignedBeaconBlock string // The file path output of an SSZ encoded SignedBeaconBlock.
|
||||||
BeaconState string // The file path output of an SSZ encoded BeaconState.
|
BeaconState string // The file path output of an SSZ encoded BeaconState.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A structure that can be utilized to mimic and existing SSZ object but change it ever so slightly.
|
||||||
|
// This is used because creating your own SSZ object is a headache.
|
||||||
|
type MimicConfig struct {
|
||||||
|
ParentRoot string // The parent root, leave it empty if you want a to use the universal
|
||||||
|
}
|
||||||
|
|
||||||
var _ = Describe("Capturehead", func() {
|
var _ = Describe("Capturehead", func() {
|
||||||
|
|
||||||
var (
|
var (
|
||||||
BC beaconclient.BeaconClient
|
|
||||||
DB sql.Database
|
|
||||||
err error
|
|
||||||
address string = "localhost"
|
address string = "localhost"
|
||||||
port int = 8080
|
port int = 8080
|
||||||
protocol string = "http"
|
protocol string = "http"
|
||||||
@ -45,10 +54,26 @@ var _ = Describe("Capturehead", func() {
|
|||||||
dbUser string = "vdbm"
|
dbUser string = "vdbm"
|
||||||
dbPassword string = "password"
|
dbPassword string = "password"
|
||||||
dbDriver string = "pgx"
|
dbDriver string = "pgx"
|
||||||
|
dummyParentRoot string = "46f98c08b54a71dfda4d56e29ec3952b8300cd8d6b67a9b6c562ae96a7a25a42"
|
||||||
)
|
)
|
||||||
|
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
TestEvents = map[string]*Message{
|
TestEvents = map[string]*Message{
|
||||||
|
"100-dummy": {
|
||||||
|
HeadMessage: beaconclient.Head{
|
||||||
|
Slot: "100",
|
||||||
|
Block: "04955400371347e26f61d7a4bbda5b23fa0b25d5fc465160f2a92d52a63b919b",
|
||||||
|
State: "36d5c9a129979b4502bd9a06e57a742810ecbc3fa55a0361c0723c92c1782bfa",
|
||||||
|
CurrentDutyDependentRoot: "",
|
||||||
|
PreviousDutyDependentRoot: "",
|
||||||
|
EpochTransition: false,
|
||||||
|
ExecutionOptimistic: false,
|
||||||
|
},
|
||||||
|
TestNotes: "An easy to process Phase 0 block",
|
||||||
|
MimicConfig: &MimicConfig{},
|
||||||
|
SignedBeaconBlock: filepath.Join("data", "100", "signed-beacon-block.ssz"),
|
||||||
|
BeaconState: filepath.Join("data", "100", "beacon-state.ssz"),
|
||||||
|
},
|
||||||
"100": {
|
"100": {
|
||||||
HeadMessage: beaconclient.Head{
|
HeadMessage: beaconclient.Head{
|
||||||
Slot: "100",
|
Slot: "100",
|
||||||
@ -59,45 +84,54 @@ var _ = Describe("Capturehead", func() {
|
|||||||
EpochTransition: false,
|
EpochTransition: false,
|
||||||
ExecutionOptimistic: false,
|
ExecutionOptimistic: false,
|
||||||
},
|
},
|
||||||
TestNotes: "This is a simple, easy to process block.",
|
TestNotes: "An easy to process Phase 0 block",
|
||||||
SignedBeaconBlock: filepath.Join("data", "100", "signed-beacon-block.ssz"),
|
SignedBeaconBlock: filepath.Join("data", "100", "signed-beacon-block.ssz"),
|
||||||
BeaconState: filepath.Join("data", "100", "beacon-state.ssz"),
|
BeaconState: filepath.Join("data", "100", "beacon-state.ssz"),
|
||||||
},
|
},
|
||||||
"101": {
|
"2375703-dummy": {
|
||||||
HeadMessage: beaconclient.Head{
|
HeadMessage: beaconclient.Head{
|
||||||
Slot: "101",
|
Slot: "2375703",
|
||||||
Block: "0xabe1a972e512182d04f0d4a5c9c25f9ee57c2e9d0ff3f4c4c82fd42d13d31083",
|
Block: "c9fb337b62e2a0dae4f27ab49913132570f7f2cab3f23ad99f4d07508a8e648e",
|
||||||
State: "0xcb04aa2edbf13c7bb7e7bd9b621ced6832e0075e89147352eac3019a824ce847",
|
State: "0299a145bcda2c8f5e7d2e068ee101861edbee2ec1db2d5e1d850b0d265aef5f",
|
||||||
CurrentDutyDependentRoot: "",
|
CurrentDutyDependentRoot: "",
|
||||||
PreviousDutyDependentRoot: "",
|
PreviousDutyDependentRoot: "",
|
||||||
EpochTransition: false,
|
EpochTransition: false,
|
||||||
ExecutionOptimistic: false,
|
ExecutionOptimistic: false,
|
||||||
},
|
},
|
||||||
TestNotes: "This is a simple, easy to process block.",
|
TestNotes: "This is a dummy message that is used for reorgs",
|
||||||
SignedBeaconBlock: filepath.Join("data", "101", "signed-beacon-block.ssz"),
|
MimicConfig: &MimicConfig{},
|
||||||
BeaconState: filepath.Join("data", "101", "beacon-state.ssz"),
|
SignedBeaconBlock: filepath.Join("data", "2375703", "signed-beacon-block.ssz"),
|
||||||
|
BeaconState: filepath.Join("data", "2375703", "beacon-state.ssz"),
|
||||||
|
},
|
||||||
|
"2375703": {
|
||||||
|
HeadMessage: beaconclient.Head{
|
||||||
|
Slot: "2375703",
|
||||||
|
Block: "0x4392372c5f6e39499e31bf924388b5815639103149f0f54f8a453773b1802301",
|
||||||
|
State: "0xb6215b560273af63ec7e011572b60ec1ca0b0232f8ff44fcd4ed55c7526e964e",
|
||||||
|
CurrentDutyDependentRoot: "", PreviousDutyDependentRoot: "", EpochTransition: false, ExecutionOptimistic: false},
|
||||||
|
ReorgMessage: beaconclient.ChainReorg{},
|
||||||
|
TestNotes: "An easy to process Altair Block",
|
||||||
|
SignedBeaconBlock: filepath.Join("data", "2375703", "signed-beacon-block.ssz"),
|
||||||
|
BeaconState: filepath.Join("data", "2375703", "beacon-state.ssz"),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
SetupBeaconNodeMock(TestEvents, protocol, address, port)
|
|
||||||
BC = *beaconclient.CreateBeaconClient(context.Background(), protocol, address, port)
|
|
||||||
DB, err = postgres.SetupPostgresDb(dbHost, dbPort, dbName, dbUser, dbPassword, dbDriver)
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
|
||||||
clearEthclDbTables(DB)
|
|
||||||
// Drop all records from the DB.
|
|
||||||
BC.Db = DB
|
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// We might also want to add an integration test that will actually process a single event, then end.
|
// We might also want to add an integration test that will actually process a single event, then end.
|
||||||
// This will help us know that our models match that actual data being served from the beacon node.
|
// This will help us know that our models match that actual data being served from the beacon node.
|
||||||
|
|
||||||
Describe("Receiving New Head SSE messages", Label("unit"), func() {
|
Describe("Receiving New Head SSE messages", Label("unit"), func() {
|
||||||
Context("Correctly formatted", func() {
|
Context("Correctly formatted Phase0 Block", func() {
|
||||||
It("Should turn it into a struct successfully.", func() {
|
It("Should turn it into a struct successfully.", func() {
|
||||||
|
|
||||||
|
BC := setUpTest(TestEvents, protocol, address, port, dummyParentRoot, dbHost, dbPort, dbName, dbUser, dbPassword, dbDriver)
|
||||||
|
SetupBeaconNodeMock(TestEvents, protocol, address, port, dummyParentRoot)
|
||||||
|
defer httpmock.Deactivate()
|
||||||
|
|
||||||
go BC.CaptureHead()
|
go BC.CaptureHead()
|
||||||
sendHeadMessage(BC, TestEvents["100"].HeadMessage)
|
sendHeadMessage(BC, TestEvents["100"].HeadMessage)
|
||||||
|
|
||||||
epoch, slot, blockRoot, stateRoot, status := queryDbSlotAndBlock(DB, TestEvents["100"].HeadMessage.Slot, TestEvents["100"].HeadMessage.Block)
|
epoch, slot, blockRoot, stateRoot, status := queryDbSlotAndBlock(BC.Db, TestEvents["100"].HeadMessage.Slot, TestEvents["100"].HeadMessage.Block)
|
||||||
Expect(slot).To(Equal(100))
|
Expect(slot).To(Equal(100))
|
||||||
Expect(epoch).To(Equal(3))
|
Expect(epoch).To(Equal(3))
|
||||||
Expect(blockRoot).To(Equal(TestEvents["100"].HeadMessage.Block))
|
Expect(blockRoot).To(Equal(TestEvents["100"].HeadMessage.Block))
|
||||||
@ -106,7 +140,27 @@ var _ = Describe("Capturehead", func() {
|
|||||||
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
//Context("A single incorrectly formatted", func() {
|
Context("Correctly formatted Altair Block", func() {
|
||||||
|
It("Should turn it into a struct successfully.", func() {
|
||||||
|
|
||||||
|
BC := setUpTest(TestEvents, protocol, address, port, dummyParentRoot, dbHost, dbPort, dbName, dbUser, dbPassword, dbDriver)
|
||||||
|
|
||||||
|
SetupBeaconNodeMock(TestEvents, protocol, address, port, dummyParentRoot)
|
||||||
|
defer httpmock.Deactivate()
|
||||||
|
|
||||||
|
go BC.CaptureHead()
|
||||||
|
sendHeadMessage(BC, TestEvents["2375703"].HeadMessage)
|
||||||
|
|
||||||
|
epoch, slot, blockRoot, stateRoot, status := queryDbSlotAndBlock(BC.Db, TestEvents["2375703"].HeadMessage.Slot, TestEvents["2375703"].HeadMessage.Block)
|
||||||
|
Expect(slot).To(Equal(2375703))
|
||||||
|
Expect(epoch).To(Equal(74240))
|
||||||
|
Expect(blockRoot).To(Equal(TestEvents["2375703"].HeadMessage.Block))
|
||||||
|
Expect(stateRoot).To(Equal(TestEvents["2375703"].HeadMessage.State))
|
||||||
|
Expect(status).To(Equal("proposed"))
|
||||||
|
|
||||||
|
})
|
||||||
|
})
|
||||||
|
//Context("A single incorrectly formatted head message", func() {
|
||||||
// It("Should create an error, maybe also add the projected slot to the knownGaps table......")
|
// It("Should create an error, maybe also add the projected slot to the knownGaps table......")
|
||||||
//})
|
//})
|
||||||
//Context("An incorrectly formatted message sandwiched between correctly formatted messages", func() {
|
//Context("An incorrectly formatted message sandwiched between correctly formatted messages", func() {
|
||||||
@ -114,10 +168,71 @@ var _ = Describe("Capturehead", func() {
|
|||||||
//})
|
//})
|
||||||
})
|
})
|
||||||
|
|
||||||
//Describe("Receiving New Reorg SSE messages", Label("unit"), func() {
|
Describe("Receiving New Reorg SSE messages", Label("dry"), func() {
|
||||||
// Context("Reorg slot is already in the DB", func() {
|
Context("Altair: Reorg slot is already in the DB", func() {
|
||||||
// It("The previous block should be marked as 'forked', the new block should be the only one marked as 'proposed'.")
|
It("The previous block should be marked as 'forked', the new block should be the only one marked as 'proposed'.", func() {
|
||||||
// })
|
|
||||||
|
BC := setUpTest(TestEvents, protocol, address, port, dummyParentRoot, dbHost, dbPort, dbName, dbUser, dbPassword, dbDriver)
|
||||||
|
SetupBeaconNodeMock(TestEvents, protocol, address, port, dummyParentRoot)
|
||||||
|
defer httpmock.Deactivate()
|
||||||
|
|
||||||
|
go BC.CaptureHead()
|
||||||
|
log.Info("Sending Altair Messages to BeaconClient")
|
||||||
|
sendHeadMessage(BC, TestEvents["2375703-dummy"].HeadMessage)
|
||||||
|
sendHeadMessage(BC, TestEvents["2375703"].HeadMessage)
|
||||||
|
|
||||||
|
for atomic.LoadUint64(&BC.Metrics.HeadTrackingReorgs) != 1 {
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Checking Altair to make sure the fork was marked properly.")
|
||||||
|
epoch, slot, blockRoot, stateRoot, status := queryDbSlotAndBlock(BC.Db, TestEvents["2375703-dummy"].HeadMessage.Slot, TestEvents["2375703-dummy"].HeadMessage.Block)
|
||||||
|
Expect(slot).To(Equal(2375703))
|
||||||
|
Expect(epoch).To(Equal(74240))
|
||||||
|
Expect(blockRoot).To(Equal(TestEvents["2375703-dummy"].HeadMessage.Block))
|
||||||
|
Expect(stateRoot).To(Equal(TestEvents["2375703-dummy"].HeadMessage.State))
|
||||||
|
Expect(status).To(Equal("forked"))
|
||||||
|
|
||||||
|
epoch, slot, blockRoot, stateRoot, status = queryDbSlotAndBlock(BC.Db, TestEvents["2375703"].HeadMessage.Slot, TestEvents["2375703"].HeadMessage.Block)
|
||||||
|
Expect(slot).To(Equal(2375703))
|
||||||
|
Expect(epoch).To(Equal(74240))
|
||||||
|
Expect(blockRoot).To(Equal(TestEvents["2375703"].HeadMessage.Block))
|
||||||
|
Expect(stateRoot).To(Equal(TestEvents["2375703"].HeadMessage.State))
|
||||||
|
Expect(status).To(Equal("proposed"))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
Context("Phase0: Reorg slot is already in the DB", func() {
|
||||||
|
It("The previous block should be marked as 'forked', the new block should be the only one marked as 'proposed'.", func() {
|
||||||
|
|
||||||
|
BC := setUpTest(TestEvents, protocol, address, port, dummyParentRoot, dbHost, dbPort, dbName, dbUser, dbPassword, dbDriver)
|
||||||
|
SetupBeaconNodeMock(TestEvents, protocol, address, port, dummyParentRoot)
|
||||||
|
defer httpmock.Deactivate()
|
||||||
|
|
||||||
|
go BC.CaptureHead()
|
||||||
|
log.Info("Sending Phase0 Messages to BeaconClient")
|
||||||
|
sendHeadMessage(BC, TestEvents["100-dummy"].HeadMessage)
|
||||||
|
sendHeadMessage(BC, TestEvents["100"].HeadMessage)
|
||||||
|
|
||||||
|
for atomic.LoadUint64(&BC.Metrics.HeadTrackingReorgs) != 1 {
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Checking Phase0 to make sure the fork was marked properly.")
|
||||||
|
epoch, slot, blockRoot, stateRoot, status := queryDbSlotAndBlock(BC.Db, TestEvents["100-dummy"].HeadMessage.Slot, TestEvents["100-dummy"].HeadMessage.Block)
|
||||||
|
Expect(slot).To(Equal(100))
|
||||||
|
Expect(epoch).To(Equal(3))
|
||||||
|
Expect(blockRoot).To(Equal(TestEvents["100-dummy"].HeadMessage.Block))
|
||||||
|
Expect(stateRoot).To(Equal(TestEvents["100-dummy"].HeadMessage.State))
|
||||||
|
Expect(status).To(Equal("forked"))
|
||||||
|
|
||||||
|
epoch, slot, blockRoot, stateRoot, status = queryDbSlotAndBlock(BC.Db, TestEvents["100"].HeadMessage.Slot, TestEvents["100"].HeadMessage.Block)
|
||||||
|
Expect(slot).To(Equal(100))
|
||||||
|
Expect(epoch).To(Equal(3))
|
||||||
|
Expect(blockRoot).To(Equal(TestEvents["100"].HeadMessage.Block))
|
||||||
|
Expect(stateRoot).To(Equal(TestEvents["100"].HeadMessage.State))
|
||||||
|
Expect(status).To(Equal("proposed"))
|
||||||
|
})
|
||||||
|
})
|
||||||
//Context("Multiple reorgs have occurred on this slot", func() {
|
//Context("Multiple reorgs have occurred on this slot", func() {
|
||||||
// It("The previous blocks should be marked as 'forked', the new block should be the only one marked as 'proposed'.")
|
// It("The previous blocks should be marked as 'forked', the new block should be the only one marked as 'proposed'.")
|
||||||
//})
|
//})
|
||||||
@ -125,7 +240,7 @@ var _ = Describe("Capturehead", func() {
|
|||||||
// It("Should simply have the correct slot in the DB.")
|
// It("Should simply have the correct slot in the DB.")
|
||||||
//})
|
//})
|
||||||
|
|
||||||
//})
|
})
|
||||||
|
|
||||||
//Describe("Querying SignedBeaconBlock and Beacon State", Label("unit"), func() {
|
//Describe("Querying SignedBeaconBlock and Beacon State", Label("unit"), func() {
|
||||||
// Context("When the slot is properly served by the beacon node", func() {
|
// Context("When the slot is properly served by the beacon node", func() {
|
||||||
@ -164,19 +279,38 @@ var _ = Describe("Capturehead", func() {
|
|||||||
//})
|
//})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Must run before each test. We can't use the beforeEach because of the way
|
||||||
|
// Ginko treats race conditions.
|
||||||
|
func setUpTest(testEvents map[string]*Message, protocol string, address string, port int, dummyParentRoot string,
|
||||||
|
dbHost string, dbPort int, dbName string, dbUser string, dbPassword string, dbDriver string) *beaconclient.BeaconClient {
|
||||||
|
|
||||||
|
BC := *beaconclient.CreateBeaconClient(context.Background(), protocol, address, port)
|
||||||
|
DB, err := postgres.SetupPostgresDb(dbHost, dbPort, dbName, dbUser, dbPassword, dbDriver)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
// Drop all records from the DB.
|
||||||
|
clearEthclDbTables(DB)
|
||||||
|
BC.Db = DB
|
||||||
|
|
||||||
|
return &BC
|
||||||
|
}
|
||||||
|
|
||||||
// Wrapper function to send a head message to the beaconclient
|
// Wrapper function to send a head message to the beaconclient
|
||||||
func sendHeadMessage(bc beaconclient.BeaconClient, head beaconclient.Head) {
|
func sendHeadMessage(bc *beaconclient.BeaconClient, head beaconclient.Head) {
|
||||||
|
|
||||||
data, err := json.Marshal(head)
|
data, err := json.Marshal(head)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
startInserts := atomic.LoadUint64(&bc.Metrics.HeadTrackingInserts)
|
||||||
bc.HeadTracking.MessagesCh <- &sse.Event{
|
bc.HeadTracking.MessagesCh <- &sse.Event{
|
||||||
ID: []byte{},
|
ID: []byte{},
|
||||||
Data: data,
|
Data: data,
|
||||||
Event: []byte{},
|
Event: []byte{},
|
||||||
Retry: []byte{},
|
Retry: []byte{},
|
||||||
}
|
}
|
||||||
time.Sleep(2 * time.Second)
|
for atomic.LoadUint64(&bc.Metrics.HeadTrackingInserts) != startInserts+1 {
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A helper function to query the ethcl.slots table based on the slot and block_root
|
// A helper function to query the ethcl.slots table based on the slot and block_root
|
||||||
@ -205,7 +339,7 @@ type TestBeaconNode struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create a new new mock for the beacon node.
|
// Create a new new mock for the beacon node.
|
||||||
func SetupBeaconNodeMock(TestEvents map[string]*Message, protocol string, address string, port int) {
|
func SetupBeaconNodeMock(TestEvents map[string]*Message, protocol string, address string, port int, dummyParentRoot string) {
|
||||||
httpmock.Activate()
|
httpmock.Activate()
|
||||||
testBC := &TestBeaconNode{
|
testBC := &TestBeaconNode{
|
||||||
TestEvents: TestEvents,
|
TestEvents: TestEvents,
|
||||||
@ -216,7 +350,7 @@ func SetupBeaconNodeMock(TestEvents map[string]*Message, protocol string, addres
|
|||||||
func(req *http.Request) (*http.Response, error) {
|
func(req *http.Request) (*http.Response, error) {
|
||||||
// Get ID from request
|
// Get ID from request
|
||||||
id := httpmock.MustGetSubmatch(req, 1)
|
id := httpmock.MustGetSubmatch(req, 1)
|
||||||
dat, err := testBC.provideSsz(id, "state")
|
dat, err := testBC.provideSsz(id, "state", dummyParentRoot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return httpmock.NewStringResponse(404, fmt.Sprintf("Unable to find file for %s", id)), err
|
return httpmock.NewStringResponse(404, fmt.Sprintf("Unable to find file for %s", id)), err
|
||||||
}
|
}
|
||||||
@ -229,7 +363,7 @@ func SetupBeaconNodeMock(TestEvents map[string]*Message, protocol string, addres
|
|||||||
func(req *http.Request) (*http.Response, error) {
|
func(req *http.Request) (*http.Response, error) {
|
||||||
// Get ID from request
|
// Get ID from request
|
||||||
id := httpmock.MustGetSubmatch(req, 1)
|
id := httpmock.MustGetSubmatch(req, 1)
|
||||||
dat, err := testBC.provideSsz(id, "block")
|
dat, err := testBC.provideSsz(id, "block", dummyParentRoot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return httpmock.NewStringResponse(404, fmt.Sprintf("Unable to find file for %s", id)), err
|
return httpmock.NewStringResponse(404, fmt.Sprintf("Unable to find file for %s", id)), err
|
||||||
}
|
}
|
||||||
@ -239,22 +373,72 @@ func SetupBeaconNodeMock(TestEvents map[string]*Message, protocol string, addres
|
|||||||
}
|
}
|
||||||
|
|
||||||
// A function to mimic querying the state from the beacon node. We simply get the SSZ file are return it.
|
// A function to mimic querying the state from the beacon node. We simply get the SSZ file are return it.
|
||||||
func (tbc TestBeaconNode) provideSsz(slotIdentifier string, sszIdentifier string) ([]byte, error) {
|
func (tbc TestBeaconNode) provideSsz(slotIdentifier string, sszIdentifier string, dummyParentRoot string) ([]byte, error) {
|
||||||
var slotFile string
|
var slotFile string
|
||||||
|
var Message *Message
|
||||||
|
|
||||||
for _, val := range tbc.TestEvents {
|
for _, val := range tbc.TestEvents {
|
||||||
if sszIdentifier == "state" {
|
if sszIdentifier == "state" {
|
||||||
if val.HeadMessage.Slot == slotIdentifier || val.HeadMessage.State == slotIdentifier {
|
if val.HeadMessage.Slot == slotIdentifier || val.HeadMessage.State == slotIdentifier {
|
||||||
slotFile = val.BeaconState
|
slotFile = val.BeaconState
|
||||||
|
Message = val
|
||||||
}
|
}
|
||||||
} else if sszIdentifier == "block" {
|
} else if sszIdentifier == "block" {
|
||||||
if val.HeadMessage.Slot == slotIdentifier || val.HeadMessage.Block == slotIdentifier {
|
if val.HeadMessage.Slot == slotIdentifier || val.HeadMessage.Block == slotIdentifier {
|
||||||
slotFile = val.SignedBeaconBlock
|
slotFile = val.SignedBeaconBlock
|
||||||
|
Message = val
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if Message.MimicConfig != nil {
|
||||||
|
log.Info("We are going to create a custom SSZ object for testing purposes.")
|
||||||
|
if sszIdentifier == "block" {
|
||||||
|
dat, err := os.ReadFile(slotFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Can't find the slot file, %s", slotFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
block := &st.SignedBeaconBlock{}
|
||||||
|
err = block.UnmarshalSSZ(dat)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Error unmarshalling: ", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
slot, err := strconv.ParseUint(Message.HeadMessage.Slot, 10, 64)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
block.Block.Slot = types.Slot(slot)
|
||||||
|
|
||||||
|
block.Block.StateRoot, err = hex.DecodeString(Message.HeadMessage.State)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
if Message.MimicConfig.ParentRoot == "" {
|
||||||
|
block.Block.ParentRoot, err = hex.DecodeString(dummyParentRoot)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
} else {
|
||||||
|
block.Block.ParentRoot, err = hex.DecodeString(Message.MimicConfig.ParentRoot)
|
||||||
|
}
|
||||||
|
return block.MarshalSSZ()
|
||||||
|
}
|
||||||
|
if sszIdentifier == "state" {
|
||||||
|
dat, err := os.ReadFile(slotFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Can't find the slot file, %s", slotFile)
|
||||||
|
}
|
||||||
|
state := st.BeaconState{}
|
||||||
|
state.UnmarshalSSZ(dat)
|
||||||
|
slot, err := strconv.ParseUint(Message.HeadMessage.Slot, 10, 64)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
state.Slot = types.Slot(slot)
|
||||||
|
return state.MarshalSSZ()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if slotFile == "" {
|
if slotFile == "" {
|
||||||
return nil, fmt.Errorf("We couldn't find the slot file for %s", slotIdentifier)
|
return nil, fmt.Errorf("We couldn't find the slot file for %s", slotIdentifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
dat, err := os.ReadFile(slotFile)
|
dat, err := os.ReadFile(slotFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Can't find the slot file, %s", slotFile)
|
return nil, fmt.Errorf("Can't find the slot file, %s", slotFile)
|
||||||
|
@ -30,9 +30,9 @@ VALUES ($1, $2, $3) ON CONFLICT (slot, state_root) DO NOTHING`
|
|||||||
INSERT INTO public.blocks (key, data)
|
INSERT INTO public.blocks (key, data)
|
||||||
VALUES ($1, $2) ON CONFLICT (key) DO NOTHING`
|
VALUES ($1, $2) ON CONFLICT (key) DO NOTHING`
|
||||||
UpdateReorgStmt string = `UPDATE ethcl.slots
|
UpdateReorgStmt string = `UPDATE ethcl.slots
|
||||||
SET status=forked
|
SET status='forked'
|
||||||
WHERE slot=$1 AND block_hash<>$2
|
WHERE slot=$1 AND block_root<>$2
|
||||||
RETURNING block_hash;`
|
RETURNING block_root;`
|
||||||
)
|
)
|
||||||
|
|
||||||
// Put all functionality to prepare the write object
|
// Put all functionality to prepare the write object
|
||||||
@ -40,6 +40,7 @@ VALUES ($1, $2) ON CONFLICT (key) DO NOTHING`
|
|||||||
// Remove any of it from the processslot file.
|
// Remove any of it from the processslot file.
|
||||||
type DatabaseWriter struct {
|
type DatabaseWriter struct {
|
||||||
Db sql.Database
|
Db sql.Database
|
||||||
|
Metrics *BeaconClientMetrics
|
||||||
DbSlots *DbSlots
|
DbSlots *DbSlots
|
||||||
DbSignedBeaconBlock *DbSignedBeaconBlock
|
DbSignedBeaconBlock *DbSignedBeaconBlock
|
||||||
DbBeaconState *DbBeaconState
|
DbBeaconState *DbBeaconState
|
||||||
@ -47,9 +48,10 @@ type DatabaseWriter struct {
|
|||||||
rawSignedBeaconBlock []byte
|
rawSignedBeaconBlock []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateDatabaseWrite(db sql.Database, slot int, stateRoot string, blockRoot string, parentBlockRoot string, status string) *DatabaseWriter {
|
func CreateDatabaseWrite(db sql.Database, slot int, stateRoot string, blockRoot string, parentBlockRoot string, status string, metrics *BeaconClientMetrics) *DatabaseWriter {
|
||||||
dw := &DatabaseWriter{
|
dw := &DatabaseWriter{
|
||||||
Db: db,
|
Db: db,
|
||||||
|
Metrics: metrics,
|
||||||
}
|
}
|
||||||
dw.prepareSlotsModel(slot, stateRoot, blockRoot, status)
|
dw.prepareSlotsModel(slot, stateRoot, blockRoot, status)
|
||||||
dw.prepareSignedBeaconBlockModel(slot, blockRoot, parentBlockRoot)
|
dw.prepareSignedBeaconBlockModel(slot, blockRoot, parentBlockRoot)
|
||||||
@ -101,6 +103,7 @@ func (dw *DatabaseWriter) writeFullSlot() {
|
|||||||
dw.writeSlots()
|
dw.writeSlots()
|
||||||
dw.writeSignedBeaconBlocks()
|
dw.writeSignedBeaconBlocks()
|
||||||
dw.writeBeaconState()
|
dw.writeBeaconState()
|
||||||
|
dw.Metrics.IncrementHeadTrackingInserts(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write the information for the generic slots table. For now this is only one function.
|
// Write the information for the generic slots table. For now this is only one function.
|
||||||
@ -151,13 +154,13 @@ func (dw *DatabaseWriter) writeBeaconState() {
|
|||||||
func (dw *DatabaseWriter) upsertBeaconState() {
|
func (dw *DatabaseWriter) upsertBeaconState() {
|
||||||
_, err := dw.Db.Exec(context.Background(), UpsertBeaconState, dw.DbBeaconState.Slot, dw.DbBeaconState.StateRoot, dw.DbBeaconState.MhKey)
|
_, err := dw.Db.Exec(context.Background(), UpsertBeaconState, dw.DbBeaconState.Slot, dw.DbBeaconState.StateRoot, dw.DbBeaconState.MhKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
loghelper.LogSlotError(dw.DbSlots.Slot, err).Error("Unable to write to the slot to the ethcl.signed_beacon_block table")
|
loghelper.LogSlotError(dw.DbSlots.Slot, err).Error("Unable to write to the slot to the ethcl.beacon_state table")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update a given slot to be marked as forked. Provide the slot and the latest latestBlockRoot.
|
// Update a given slot to be marked as forked. Provide the slot and the latest latestBlockRoot.
|
||||||
// We will mark all entries for the given slot that don't match the provided latestBlockRoot as forked.
|
// We will mark all entries for the given slot that don't match the provided latestBlockRoot as forked.
|
||||||
func updateReorgs(db sql.Database, slot string, latestBlockRoot string) (int64, error) {
|
func updateReorgs(db sql.Database, slot string, latestBlockRoot string, metrics *BeaconClientMetrics) (int64, error) {
|
||||||
res, err := db.Exec(context.Background(), UpdateReorgStmt, slot, latestBlockRoot)
|
res, err := db.Exec(context.Background(), UpdateReorgStmt, slot, latestBlockRoot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
loghelper.LogReorgError(slot, latestBlockRoot, err).Error("We are unable to update the ethcl.slots table with reorgs.")
|
loghelper.LogReorgError(slot, latestBlockRoot, err).Error("We are unable to update the ethcl.slots table with reorgs.")
|
||||||
@ -168,6 +171,7 @@ func updateReorgs(db sql.Database, slot string, latestBlockRoot string) (int64,
|
|||||||
loghelper.LogReorgError(slot, latestBlockRoot, err).Error("Unable to figure out how many entries were effected by the reorg.")
|
loghelper.LogReorgError(slot, latestBlockRoot, err).Error("Unable to figure out how many entries were effected by the reorg.")
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
metrics.IncrementHeadTrackingReorgs(1)
|
||||||
|
|
||||||
return count, nil
|
return count, nil
|
||||||
}
|
}
|
||||||
|
15
pkg/beaconclient/metrics.go
Normal file
15
pkg/beaconclient/metrics.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package beaconclient
|
||||||
|
|
||||||
|
import "sync/atomic"
|
||||||
|
|
||||||
|
// Wrapper function to increment inserts. If we want to use mutexes later we can easily update all
|
||||||
|
// occurrences here.
|
||||||
|
func (m *BeaconClientMetrics) IncrementHeadTrackingInserts(inc uint64) {
|
||||||
|
atomic.AddUint64(&m.HeadTrackingInserts, inc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrapper function to increment reorgs. If we want to use mutexes later we can easily update all
|
||||||
|
// occurrences here.
|
||||||
|
func (m *BeaconClientMetrics) IncrementHeadTrackingReorgs(inc uint64) {
|
||||||
|
atomic.AddUint64(&m.HeadTrackingReorgs, inc)
|
||||||
|
}
|
@ -17,7 +17,7 @@ func (bc *BeaconClient) handleReorg() {
|
|||||||
for {
|
for {
|
||||||
reorg := <-bc.ReOrgTracking.ProcessCh
|
reorg := <-bc.ReOrgTracking.ProcessCh
|
||||||
log.WithFields(log.Fields{"reorg": reorg}).Debug("Received a new reorg message.")
|
log.WithFields(log.Fields{"reorg": reorg}).Debug("Received a new reorg message.")
|
||||||
processReorg(bc.Db, reorg.Slot, reorg.NewHeadBlock)
|
processReorg(bc.Db, reorg.Slot, reorg.NewHeadBlock, bc.Metrics)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ func (bc *BeaconClient) handleHead() {
|
|||||||
err: fmt.Errorf("Unable to turn the slot from string to int: %s", head.Slot),
|
err: fmt.Errorf("Unable to turn the slot from string to int: %s", head.Slot),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err = processHeadSlot(bc.Db, bc.ServerEndpoint, slot, head.Block, head.State, bc.PreviousSlot, bc.PreviousBlockRoot)
|
err = processHeadSlot(bc.Db, bc.ServerEndpoint, slot, head.Block, head.State, bc.PreviousSlot, bc.PreviousBlockRoot, bc.Metrics)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
loghelper.LogSlotError(head.Slot, err)
|
loghelper.LogSlotError(head.Slot, err)
|
||||||
}
|
}
|
||||||
|
@ -6,12 +6,8 @@ import (
|
|||||||
"github.com/vulcanize/ipld-ethcl-indexer/pkg/loghelper"
|
"github.com/vulcanize/ipld-ethcl-indexer/pkg/loghelper"
|
||||||
)
|
)
|
||||||
|
|
||||||
func processReorg(db sql.Database, slot string, latestBlockRoot string) {
|
func processReorg(db sql.Database, slot string, latestBlockRoot string, metrics *BeaconClientMetrics) {
|
||||||
// Check to see if there are slots in the DB with the given slot.
|
updatedRows, err := updateReorgs(db, slot, latestBlockRoot, metrics)
|
||||||
// Update them ALL to forked
|
|
||||||
// Upsert the new slot into the DB, mark the status to proposed.
|
|
||||||
// Query at the end to make sure that you have handled the reorg properly.
|
|
||||||
updatedRows, err := updateReorgs(db, slot, latestBlockRoot)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Add this slot to the knownGaps table..
|
// Add this slot to the knownGaps table..
|
||||||
|
@ -38,6 +38,7 @@ type ProcessSlot struct {
|
|||||||
Status string // The status of the block
|
Status string // The status of the block
|
||||||
HeadOrHistoric string // Is this the head or a historic slot. This is critical when trying to analyze errors and missed slots.
|
HeadOrHistoric string // Is this the head or a historic slot. This is critical when trying to analyze errors and missed slots.
|
||||||
Db sql.Database // The DB object used to write to the DB.
|
Db sql.Database // The DB object used to write to the DB.
|
||||||
|
Metrics *BeaconClientMetrics // An object to keep track of the beaconclient metrics
|
||||||
// BeaconBlock
|
// BeaconBlock
|
||||||
|
|
||||||
SszSignedBeaconBlock []byte // The entire SSZ encoded SignedBeaconBlock
|
SszSignedBeaconBlock []byte // The entire SSZ encoded SignedBeaconBlock
|
||||||
@ -54,7 +55,7 @@ type ProcessSlot struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This function will do all the work to process the slot and write it to the DB.
|
// This function will do all the work to process the slot and write it to the DB.
|
||||||
func processFullSlot(db sql.Database, serverAddress string, slot int, blockRoot string, stateRoot string, previousSlot int, previousBlockRoot string, headOrHistoric string) error {
|
func processFullSlot(db sql.Database, serverAddress string, slot int, blockRoot string, stateRoot string, previousSlot int, previousBlockRoot string, headOrHistoric string, metrics *BeaconClientMetrics) error {
|
||||||
headOrHistoric = strings.ToLower(headOrHistoric)
|
headOrHistoric = strings.ToLower(headOrHistoric)
|
||||||
if headOrHistoric != "head" && headOrHistoric != "historic" {
|
if headOrHistoric != "head" && headOrHistoric != "historic" {
|
||||||
return fmt.Errorf("headOrBatch must be either historic or head!")
|
return fmt.Errorf("headOrBatch must be either historic or head!")
|
||||||
@ -64,6 +65,8 @@ func processFullSlot(db sql.Database, serverAddress string, slot int, blockRoot
|
|||||||
BlockRoot: blockRoot,
|
BlockRoot: blockRoot,
|
||||||
StateRoot: stateRoot,
|
StateRoot: stateRoot,
|
||||||
HeadOrHistoric: headOrHistoric,
|
HeadOrHistoric: headOrHistoric,
|
||||||
|
Db: db,
|
||||||
|
Metrics: metrics,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the SignedBeaconBlock.
|
// Get the SignedBeaconBlock.
|
||||||
@ -86,7 +89,7 @@ func processFullSlot(db sql.Database, serverAddress string, slot int, blockRoot
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get this object ready to write
|
// Get this object ready to write
|
||||||
dw := ps.createWriteObjects(db)
|
dw := ps.createWriteObjects()
|
||||||
|
|
||||||
// Write the object to the DB.
|
// Write the object to the DB.
|
||||||
dw.writeFullSlot()
|
dw.writeFullSlot()
|
||||||
@ -95,8 +98,8 @@ func processFullSlot(db sql.Database, serverAddress string, slot int, blockRoot
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handle a slot that is at head. A wrapper function for calling `handleFullSlot`.
|
// Handle a slot that is at head. A wrapper function for calling `handleFullSlot`.
|
||||||
func processHeadSlot(db sql.Database, serverAddress string, slot int, blockRoot string, stateRoot string, previousSlot int, previousBlockRoot string) error {
|
func processHeadSlot(db sql.Database, serverAddress string, slot int, blockRoot string, stateRoot string, previousSlot int, previousBlockRoot string, metrics *BeaconClientMetrics) error {
|
||||||
return processFullSlot(db, serverAddress, slot, blockRoot, stateRoot, previousSlot, previousBlockRoot, "head")
|
return processFullSlot(db, serverAddress, slot, blockRoot, stateRoot, previousSlot, previousBlockRoot, "head", metrics)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle a historic slot. A wrapper function for calling `handleFullSlot`.
|
// Handle a historic slot. A wrapper function for calling `handleFullSlot`.
|
||||||
@ -179,7 +182,7 @@ func (ps *ProcessSlot) checkPreviousSlot(previousSlot int, previousBlockRoot str
|
|||||||
"slot": ps.FullBeaconState.Slot,
|
"slot": ps.FullBeaconState.Slot,
|
||||||
"fork": true,
|
"fork": true,
|
||||||
}).Warn("A fork occurred! The previous slot and current slot match.")
|
}).Warn("A fork occurred! The previous slot and current slot match.")
|
||||||
processReorg(ps.Db, strconv.Itoa(ps.Slot), ps.BlockRoot)
|
processReorg(ps.Db, strconv.Itoa(ps.Slot), ps.BlockRoot, ps.Metrics)
|
||||||
} else if previousSlot-1 != int(ps.FullBeaconState.Slot) {
|
} else if previousSlot-1 != int(ps.FullBeaconState.Slot) {
|
||||||
log.WithFields(log.Fields{
|
log.WithFields(log.Fields{
|
||||||
"previousSlot": previousSlot,
|
"previousSlot": previousSlot,
|
||||||
@ -192,7 +195,7 @@ func (ps *ProcessSlot) checkPreviousSlot(previousSlot int, previousBlockRoot str
|
|||||||
"previousBlockRoot": previousBlockRoot,
|
"previousBlockRoot": previousBlockRoot,
|
||||||
"currentBlockParent": parentRoot,
|
"currentBlockParent": parentRoot,
|
||||||
}).Error("The previousBlockRoot does not match the current blocks parent, an unprocessed fork might have occurred.")
|
}).Error("The previousBlockRoot does not match the current blocks parent, an unprocessed fork might have occurred.")
|
||||||
processReorg(ps.Db, strconv.Itoa(previousSlot), parentRoot)
|
processReorg(ps.Db, strconv.Itoa(previousSlot), parentRoot, ps.Metrics)
|
||||||
// Call our batch processing function.
|
// Call our batch processing function.
|
||||||
// Continue with this slot.
|
// Continue with this slot.
|
||||||
} else {
|
} else {
|
||||||
@ -216,7 +219,7 @@ func (ps *ProcessSlot) checkMissedSlot() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Transforms all the raw data into DB models that can be written to the DB.
|
// Transforms all the raw data into DB models that can be written to the DB.
|
||||||
func (ps *ProcessSlot) createWriteObjects(db sql.Database) *DatabaseWriter {
|
func (ps *ProcessSlot) createWriteObjects() *DatabaseWriter {
|
||||||
var (
|
var (
|
||||||
stateRoot string
|
stateRoot string
|
||||||
blockRoot string
|
blockRoot string
|
||||||
@ -251,7 +254,7 @@ func (ps *ProcessSlot) createWriteObjects(db sql.Database) *DatabaseWriter {
|
|||||||
status = "proposed"
|
status = "proposed"
|
||||||
}
|
}
|
||||||
|
|
||||||
dw := CreateDatabaseWrite(db, ps.Slot, stateRoot, blockRoot, ps.ParentBlockRoot, status)
|
dw := CreateDatabaseWrite(ps.Db, ps.Slot, stateRoot, blockRoot, ps.ParentBlockRoot, status, ps.Metrics)
|
||||||
dw.rawSignedBeaconBlock = ps.SszSignedBeaconBlock
|
dw.rawSignedBeaconBlock = ps.SszSignedBeaconBlock
|
||||||
dw.rawBeaconState = ps.SszBeaconState
|
dw.rawBeaconState = ps.SszBeaconState
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user