diff --git a/go.mod b/go.mod index 061de091..3d1f3377 100644 --- a/go.mod +++ b/go.mod @@ -14,6 +14,7 @@ require ( github.com/prometheus/client_golang v1.14.0 github.com/sirupsen/logrus v1.9.3 golang.org/x/crypto v0.41.0 + golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f google.golang.org/protobuf v1.36.6 ) @@ -103,7 +104,6 @@ require ( github.com/tklauser/numcpus v0.6.1 // indirect github.com/urfave/cli/v2 v2.27.5 // indirect github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect - golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f // indirect golang.org/x/mod v0.27.0 // indirect golang.org/x/net v0.43.0 // indirect golang.org/x/sync v0.16.0 // indirect diff --git a/internal/mt/mt.go b/internal/mt/mt.go new file mode 100644 index 00000000..90506727 --- /dev/null +++ b/internal/mt/mt.go @@ -0,0 +1,133 @@ +// In-memory Merkle Tree which implements an authenticated list. +package mt + +import ( + "crypto/sha256" + "fmt" + "iter" +) + +type Digest = [sha256.Size]byte + +var MerklePlaceholderDigest = Digest([]byte("MERKLE_PLACEHOLDER_HASH_________")) +var LeafSeparator = []byte("MT::LeafNode") +var InternalSeparator = []byte("MT::InternalNode") + +func digestInternal(leftChildDigest Digest, rightChildDigest Digest) Digest { + hash := sha256.New() + hash.Write(InternalSeparator) + hash.Write(leftChildDigest[:]) + hash.Write(rightChildDigest[:]) + return Digest(hash.Sum(nil)) +} + +func digestLeaf(preimage []byte) Digest { + hash := sha256.New() + hash.Write(LeafSeparator) + hash.Write(preimage) + return Digest(hash.Sum(nil)) +} + +func buildTreeLevels(leafPreimages [][]byte) iter.Seq[[]Digest] { + return func(yield func([]Digest) bool) { + leafCount := len(leafPreimages) + if leafCount == 0 { + if !yield([]Digest{MerklePlaceholderDigest}) { + return + } + } + + // Start with the leaf digests + currentLayer := make([]Digest, leafCount) + for i, leafPreimage := range leafPreimages { + currentLayer[i] = digestLeaf(leafPreimage) + } + if !yield(currentLayer) { + return + } + + // Build the tree upwards, padding with placeholders when odd number of nodes + for len(currentLayer) > 1 { + nextLayerSize := (len(currentLayer) + 1) / 2 // Ceiling division + nextLayer := make([]Digest, 0, nextLayerSize) + + for i := 0; i < len(currentLayer); i += 2 { + leftDigest := currentLayer[i] + rightDigest := MerklePlaceholderDigest + if i+1 < len(currentLayer) { + rightDigest = currentLayer[i+1] + } + nextLayer = append(nextLayer, digestInternal(leftDigest, rightDigest)) + } + currentLayer = nextLayer + if !yield(currentLayer) { + return + } + } + } +} + +// Root computes the Merkle tree root from leaf preimages. +func Root(leafPreimages [][]byte) Digest { + var rootDigest Digest + for treeLevel := range buildTreeLevels(leafPreimages) { + if len(treeLevel) == 1 { + rootDigest = treeLevel[0] + } + } + return rootDigest +} + +// Prove generates a Merkle inclusion proof that the leafPreimage at index is +// included in the tree rooted at Root(leafPreimages). +func Prove(leafPreimages [][]byte, index uint64) ([]Digest, error) { + leafCount := len(leafPreimages) + if leafCount == 0 { + return nil, fmt.Errorf("cannot prove inclusion in empty tree") + } + if index >= uint64(leafCount) { + return nil, fmt.Errorf("index %d is out of bounds for %d leaves", index, leafCount) + } + + var proof []Digest + currentIndex := index + + for treeLevel := range buildTreeLevels(leafPreimages) { + if len(treeLevel) <= 1 { + break + } + siblingIndex := currentIndex ^ 1 + siblingDigest := MerklePlaceholderDigest + if siblingIndex < uint64(len(treeLevel)) { + siblingDigest = treeLevel[siblingIndex] + } + proof = append(proof, siblingDigest) + currentIndex /= 2 + } + + return proof, nil +} + +// Verify verifies that leafPreimage is preimage of the index-th leaf in the +// Merkle tree rooted at expectedRootDigest. +func Verify(expectedRootDigest Digest, index uint64, leafPreimage []byte, proof []Digest) error { + currentDigest := digestLeaf(leafPreimage) + currentIndex := index + + for _, siblingDigest := range proof { + if currentIndex%2 == 0 { + // Current node is left child, sibling is right + currentDigest = digestInternal(currentDigest, siblingDigest) + } else { + // Current node is right child, sibling is left + currentDigest = digestInternal(siblingDigest, currentDigest) + } + currentIndex /= 2 + } + + if currentDigest != expectedRootDigest { + return fmt.Errorf("computed root digest mismatch: computed %x, expected %x", currentDigest, expectedRootDigest) + } + + return nil +} diff --git a/internal/util/generic.go b/internal/util/generic.go index 95950699..c4711523 100644 --- a/internal/util/generic.go +++ b/internal/util/generic.go @@ -1,9 +1,19 @@ package util +import "golang.org/x/exp/constraints" + func PointerTo[T any](v T) *T { return &v } +func PointerIntegerCast[U constraints.Integer, T constraints.Integer](p *T) *U { + if p == nil { + return nil + } + v := U(*p) + return &v +} + func NilCoalesce[T any](maybe *T, default_ T) T { if maybe != nil { return *maybe diff --git a/networking/ragedisco/discovery_protocol.go b/networking/ragedisco/discovery_protocol.go index 0218834b..99b4798d 100644 --- a/networking/ragedisco/discovery_protocol.go +++ b/networking/ragedisco/discovery_protocol.go @@ -20,6 +20,7 @@ import ( // Maximum number of distinct oracles that we can have across groups. // The exact number is chosen arbitrarily. Better to have an arbitrary limit // than no limit. +// See also [ragetypes.MaxPeersPerHost]. const MaxOracles = 165 type incomingMessage struct { diff --git a/offchainreporting2plus/internal/config/netconfig/netconfig.go b/offchainreporting2plus/internal/config/netconfig/netconfig.go index c5f7c1f5..dde01af0 100644 --- a/offchainreporting2plus/internal/config/netconfig/netconfig.go +++ b/offchainreporting2plus/internal/config/netconfig/netconfig.go @@ -5,6 +5,7 @@ import ( "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config" "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr2config" + "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config" "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3config" "github.com/smartcontractkit/libocr/offchainreporting2plus/types" ) @@ -37,6 +38,16 @@ func NetConfigFromContractConfig(contractConfig types.ContractConfig) (NetConfig publicConfig.F, peerIDs(publicConfig.OracleIdentities), }, nil + case config.OCR3_1OffchainConfigVersion: + publicConfig, err := ocr3_1config.PublicConfigFromContractConfig(true, contractConfig) + if err != nil { + return NetConfig{}, err + } + return NetConfig{ + publicConfig.ConfigDigest, + publicConfig.F, + peerIDs(publicConfig.OracleIdentities), + }, nil default: return NetConfig{}, fmt.Errorf("NetConfigFromContractConfig received OffchainConfigVersion %v", contractConfig.OffchainConfigVersion) } diff --git a/offchainreporting2plus/internal/config/ocr3_1config/defaults.go b/offchainreporting2plus/internal/config/ocr3_1config/defaults.go new file mode 100644 index 00000000..fe609f6b --- /dev/null +++ b/offchainreporting2plus/internal/config/ocr3_1config/defaults.go @@ -0,0 +1,91 @@ +package ocr3_1config + +import ( + "math" + "time" + + "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/ocr3_1/maxmaxserializationlimits" + "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3_1types" + "github.com/smartcontractkit/libocr/offchainreporting2plus/types" +) + +const ( + defaultSmallRequestSizeMinRequestToSameOracleInterval = 10 * time.Millisecond + + assumedRTT = 500 * time.Millisecond + assumedBandwidthBitsPerSecond = 100e6 // 100Mbit + assumedBandwidthBytesPerSecond = assumedBandwidthBitsPerSecond / 8 +) + +// transferDuration calculates the duration required to transfer the given +// number of bytes at the assumed bandwidth +func transferDuration(bytes int) time.Duration { + seconds := float64(bytes) / float64(assumedBandwidthBytesPerSecond) + return time.Duration(seconds * float64(time.Second)) +} + +func roundUpToTenthOfSecond(duration time.Duration) time.Duration { + tenthsOfSecond := float64(duration.Milliseconds()) / 100 + return time.Duration(math.Ceil(tenthsOfSecond)) * 100 * time.Millisecond +} + +func DefaultDeltaInitial() time.Duration { + return roundUpToTenthOfSecond( + 3*assumedRTT/2 + + transferDuration(maxmaxserializationlimits.MaxMaxEpochStartRequestBytes*types.MaxOracles+maxmaxserializationlimits.MaxMaxEpochStartBytes)) +} + +func DefaultDeltaReportsPlusPrecursorRequest() time.Duration { + return roundUpToTenthOfSecond( + assumedRTT + + transferDuration(maxmaxserializationlimits.MaxMaxReportsPlusPrecursorRequestBytes+maxmaxserializationlimits.MaxMaxReportsPlusPrecursorBytes)) +} + +func DefaultDeltaBlockSyncResponseTimeout() time.Duration { + return roundUpToTenthOfSecond( + assumedRTT + + transferDuration(maxmaxserializationlimits.MaxMaxBlockSyncRequestBytes+maxmaxserializationlimits.MaxMaxBlockSyncResponseBytes)) +} + +func DefaultDeltaTreeSyncResponseTimeout() time.Duration { + return roundUpToTenthOfSecond( + assumedRTT + + transferDuration(maxmaxserializationlimits.MaxMaxTreeSyncChunkRequestBytes+maxmaxserializationlimits.MaxMaxTreeSyncChunkResponseBytes)) +} + +func DefaultDeltaBlobChunkResponseTimeout() time.Duration { + return roundUpToTenthOfSecond( + assumedRTT + + transferDuration(maxmaxserializationlimits.MaxMaxBlobChunkRequestBytes+maxmaxserializationlimits.MaxMaxBlobChunkResponseBytes)) +} + +const ( + DefaultDeltaResend = 5 * time.Second + + DefaultDeltaStateSyncSummaryInterval = 5 * time.Second + DefaultDeltaBlockSyncMinRequestToSameOracleInterval = defaultSmallRequestSizeMinRequestToSameOracleInterval + + DefaultMaxBlocksPerBlockSyncResponse = 2 + DefaultMaxParallelRequestedBlocks = 100 + + DefaultDeltaTreeSyncMinRequestToSameOracleInterval = defaultSmallRequestSizeMinRequestToSameOracleInterval + + DefaultMaxTreeSyncChunkKeys = 1024 + + // A tree sync chunk must always fit at least 1 maximally sized (using maxmax) key-value pair + DefaultMaxTreeSyncChunkKeysPlusValuesBytes = ocr3_1types.MaxMaxKeyValueKeyBytes + ocr3_1types.MaxMaxKeyValueValueBytes + + DefaultMaxParallelTreeSyncChunkFetches = 8 + + DefaultSnapshotInterval = 10_000 + DefaultMaxHistoricalSnapshotsRetained = 10 + + DefaultDeltaBlobOfferMinRequestToSameOracleInterval = defaultSmallRequestSizeMinRequestToSameOracleInterval + DefaultDeltaBlobOfferResponseTimeout = 10 * time.Second + + DefaultDeltaBlobBroadcastGrace = 10 * time.Millisecond + + DefaultDeltaBlobChunkMinRequestToSameOracleInterval = defaultSmallRequestSizeMinRequestToSameOracleInterval + + DefaultBlobChunkBytes = 1_000_000 // 1MB +) diff --git a/offchainreporting2plus/internal/config/ocr3_1config/max_max.go b/offchainreporting2plus/internal/config/ocr3_1config/max_max.go new file mode 100644 index 00000000..e0ef21ea --- /dev/null +++ b/offchainreporting2plus/internal/config/ocr3_1config/max_max.go @@ -0,0 +1,8 @@ +package ocr3_1config + +const ( + MaxMaxBlocksPerBlockSyncResponse = 2 + MaxMaxTreeSyncChunkKeys = 10_000 + MaxMaxTreeSyncChunkKeysPlusValuesBytes = 50_000_000 // 50MB + MaxMaxBlobChunkBytes = 10_000_000 // 10MB +) diff --git a/offchainreporting2plus/internal/config/ocr3_1config/metrics.go b/offchainreporting2plus/internal/config/ocr3_1config/metrics.go new file mode 100644 index 00000000..3ad92d7c --- /dev/null +++ b/offchainreporting2plus/internal/config/ocr3_1config/metrics.go @@ -0,0 +1,452 @@ +package ocr3_1config + +import ( + "github.com/prometheus/client_golang/prometheus" + "github.com/smartcontractkit/libocr/commontypes" + "github.com/smartcontractkit/libocr/internal/metricshelper" +) + +type PublicConfigMetrics struct { + registerer prometheus.Registerer + deltaProgress prometheus.Gauge + deltaResend prometheus.Gauge + deltaInitial prometheus.Gauge + deltaRound prometheus.Gauge + deltaGrace prometheus.Gauge + deltaReportsPlusPrecursorRequest prometheus.Gauge + deltaStage prometheus.Gauge + + // state sync + deltaStateSyncSummaryInterval prometheus.Gauge + + // block sync + deltaBlockSyncMinRequestToSameOracleInterval prometheus.Gauge + deltaBlockSyncResponseTimeout prometheus.Gauge + maxBlocksPerBlockSyncResponse prometheus.Gauge + maxParallelRequestedBlocks prometheus.Gauge + + // tree sync + deltaTreeSyncMinRequestToSameOracleInterval prometheus.Gauge + deltaTreeSyncResponseTimeout prometheus.Gauge + maxTreeSyncChunkKeys prometheus.Gauge + maxTreeSyncChunkKeysPlusValuesBytes prometheus.Gauge + maxParallelTreeSyncChunkFetches prometheus.Gauge + + // snapshotting + snapshotInterval prometheus.Gauge + maxHistoricalSnapshotsRetained prometheus.Gauge + + // blobs + deltaBlobOfferMinRequestToSameOracleInterval prometheus.Gauge + deltaBlobOfferResponseTimeout prometheus.Gauge + deltaBlobBroadcastGrace prometheus.Gauge + deltaBlobChunkMinRequestToSameOracleInterval prometheus.Gauge + deltaBlobChunkResponseTimeout prometheus.Gauge + blobChunkBytes prometheus.Gauge + + rMax prometheus.Gauge + // skip S + + maxDurationInitialization prometheus.Gauge + warnDurationQuery prometheus.Gauge + warnDurationObservation prometheus.Gauge + warnDurationValidateObservation prometheus.Gauge + warnDurationObservationQuorum prometheus.Gauge + warnDurationStateTransition prometheus.Gauge + warnDurationCommitted prometheus.Gauge + maxDurationShouldAcceptAttestedReport prometheus.Gauge + maxDurationShouldTransmitAcceptedReport prometheus.Gauge + + n prometheus.Gauge + f prometheus.Gauge + + minRoundInterval prometheus.Gauge +} + +func NewPublicConfigMetrics( + registerer prometheus.Registerer, + logger commontypes.Logger, + publicConfig PublicConfig, +) *PublicConfigMetrics { + + deltaProgress := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "ocr3_1_config_delta_progress_seconds", + Help: "See https://pkg.go.dev/github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config#PublicConfig for details", + }) + deltaProgress.Set(publicConfig.DeltaProgress.Seconds()) + metricshelper.RegisterOrLogError(logger, registerer, deltaProgress, "ocr3_1_config_delta_progress_seconds") + + deltaResend := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "ocr3_1_config_delta_resend_seconds", + Help: "See https://pkg.go.dev/github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config#PublicConfig for details", + }) + deltaResend.Set(publicConfig.GetDeltaResend().Seconds()) + metricshelper.RegisterOrLogError(logger, registerer, deltaResend, "ocr3_1_config_delta_resend_seconds") + + deltaInitial := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "ocr3_1_config_delta_initial_seconds", + Help: "See https://pkg.go.dev/github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config#PublicConfig for details", + }) + deltaInitial.Set(publicConfig.GetDeltaInitial().Seconds()) + metricshelper.RegisterOrLogError(logger, registerer, deltaInitial, "ocr3_1_config_delta_initial_seconds") + + deltaRound := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "ocr3_1_config_delta_round_seconds", + Help: "See https://pkg.go.dev/github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config#PublicConfig for details", + }) + deltaRound.Set(publicConfig.DeltaRound.Seconds()) + metricshelper.RegisterOrLogError(logger, registerer, deltaRound, "ocr3_1_config_delta_round_seconds") + + deltaGrace := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "ocr3_1_config_delta_grace_seconds", + Help: "See https://pkg.go.dev/github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config#PublicConfig for details", + }) + deltaGrace.Set(publicConfig.DeltaGrace.Seconds()) + metricshelper.RegisterOrLogError(logger, registerer, deltaGrace, "ocr3_1_config_delta_grace_seconds") + + deltaReportsPlusPrecursorRequest := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "ocr3_1_config_delta_reports_plus_precursor_request_seconds", + Help: "See https://pkg.go.dev/github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config#PublicConfig for details", + }) + deltaReportsPlusPrecursorRequest.Set(publicConfig.GetDeltaReportsPlusPrecursorRequest().Seconds()) + metricshelper.RegisterOrLogError(logger, registerer, deltaReportsPlusPrecursorRequest, "ocr3_1_config_delta_reports_plus_precursor_request_seconds") + + deltaStage := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "ocr3_1_config_delta_stage_seconds", + Help: "See https://pkg.go.dev/github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config#PublicConfig for details", + }) + deltaStage.Set(publicConfig.DeltaStage.Seconds()) + metricshelper.RegisterOrLogError(logger, registerer, deltaStage, "ocr3_1_config_delta_stage_seconds") + + // state sync + deltaStateSyncSummaryInterval := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "ocr3_1_config_delta_state_sync_summary_interval_seconds", + Help: "See https://pkg.go.dev/github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config#PublicConfig for details", + }) + deltaStateSyncSummaryInterval.Set(publicConfig.GetDeltaStateSyncSummaryInterval().Seconds()) + metricshelper.RegisterOrLogError(logger, registerer, deltaStateSyncSummaryInterval, "ocr3_1_config_delta_state_sync_summary_interval_seconds") + + // block sync + deltaBlockSyncMinRequestToSameOracleInterval := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "ocr3_1_config_delta_block_sync_min_request_to_same_oracle_interval_seconds", + Help: "See https://pkg.go.dev/github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config#PublicConfig for details", + }) + deltaBlockSyncMinRequestToSameOracleInterval.Set(publicConfig.GetDeltaBlockSyncMinRequestToSameOracleInterval().Seconds()) + metricshelper.RegisterOrLogError(logger, registerer, deltaBlockSyncMinRequestToSameOracleInterval, "ocr3_1_config_delta_block_sync_min_request_to_same_oracle_interval_seconds") + + deltaBlockSyncResponseTimeout := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "ocr3_1_config_delta_block_sync_response_timeout_seconds", + Help: "See https://pkg.go.dev/github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config#PublicConfig for details", + }) + deltaBlockSyncResponseTimeout.Set(publicConfig.GetDeltaBlockSyncResponseTimeout().Seconds()) + metricshelper.RegisterOrLogError(logger, registerer, deltaBlockSyncResponseTimeout, "ocr3_1_config_delta_block_sync_response_timeout_seconds") + + maxBlocksPerBlockSyncResponse := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "ocr3_1_config_max_blocks_per_block_sync_response", + Help: "See https://pkg.go.dev/github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config#PublicConfig for details", + }) + maxBlocksPerBlockSyncResponse.Set(float64(publicConfig.GetMaxBlocksPerBlockSyncResponse())) + metricshelper.RegisterOrLogError(logger, registerer, maxBlocksPerBlockSyncResponse, "ocr3_1_config_max_blocks_per_block_sync_response") + + maxParallelRequestedBlocks := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "ocr3_1_config_max_parallel_requested_blocks", + Help: "See https://pkg.go.dev/github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config#PublicConfig for details", + }) + maxParallelRequestedBlocks.Set(float64(publicConfig.GetMaxParallelRequestedBlocks())) + metricshelper.RegisterOrLogError(logger, registerer, maxParallelRequestedBlocks, "ocr3_1_config_max_parallel_requested_blocks") + + // tree sync + deltaTreeSyncMinRequestToSameOracleInterval := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "ocr3_1_config_delta_tree_sync_min_request_to_same_oracle_interval_seconds", + Help: "See https://pkg.go.dev/github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config#PublicConfig for details", + }) + deltaTreeSyncMinRequestToSameOracleInterval.Set(publicConfig.GetDeltaTreeSyncMinRequestToSameOracleInterval().Seconds()) + metricshelper.RegisterOrLogError(logger, registerer, deltaTreeSyncMinRequestToSameOracleInterval, "ocr3_1_config_delta_tree_sync_min_request_to_same_oracle_interval_seconds") + + deltaTreeSyncResponseTimeout := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "ocr3_1_config_delta_tree_sync_response_timeout_seconds", + Help: "See https://pkg.go.dev/github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config#PublicConfig for details", + }) + deltaTreeSyncResponseTimeout.Set(publicConfig.GetDeltaTreeSyncResponseTimeout().Seconds()) + metricshelper.RegisterOrLogError(logger, registerer, deltaTreeSyncResponseTimeout, "ocr3_1_config_delta_tree_sync_response_timeout_seconds") + + maxTreeSyncChunkKeys := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "ocr3_1_config_max_tree_sync_chunk_keys", + Help: "See https://pkg.go.dev/github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config#PublicConfig for details", + }) + maxTreeSyncChunkKeys.Set(float64(publicConfig.GetMaxTreeSyncChunkKeys())) + metricshelper.RegisterOrLogError(logger, registerer, maxTreeSyncChunkKeys, "ocr3_1_config_max_tree_sync_chunk_keys") + + maxTreeSyncChunkKeysPlusValuesBytes := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "ocr3_1_config_max_tree_sync_chunk_keys_plus_values_bytes", + Help: "See https://pkg.go.dev/github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config#PublicConfig for details", + }) + maxTreeSyncChunkKeysPlusValuesBytes.Set(float64(publicConfig.GetMaxTreeSyncChunkKeysPlusValuesBytes())) + metricshelper.RegisterOrLogError(logger, registerer, maxTreeSyncChunkKeysPlusValuesBytes, "ocr3_1_config_max_tree_sync_chunk_keys_plus_values_bytes") + + maxParallelTreeSyncChunkFetches := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "ocr3_1_config_max_parallel_tree_sync_chunk_fetches", + Help: "See https://pkg.go.dev/github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config#PublicConfig for details", + }) + maxParallelTreeSyncChunkFetches.Set(float64(publicConfig.GetMaxParallelTreeSyncChunkFetches())) + metricshelper.RegisterOrLogError(logger, registerer, maxParallelTreeSyncChunkFetches, "ocr3_1_config_max_parallel_tree_sync_chunk_fetches") + + // snapshotting + snapshotInterval := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "ocr3_1_config_snapshot_interval", + Help: "See https://pkg.go.dev/github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config#PublicConfig for details", + }) + snapshotInterval.Set(float64(publicConfig.GetSnapshotInterval())) + metricshelper.RegisterOrLogError(logger, registerer, snapshotInterval, "ocr3_1_config_snapshot_interval") + + maxHistoricalSnapshotsRetained := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "ocr3_1_config_max_historical_snapshots_retained", + Help: "See https://pkg.go.dev/github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config#PublicConfig for details", + }) + maxHistoricalSnapshotsRetained.Set(float64(publicConfig.GetMaxHistoricalSnapshotsRetained())) + metricshelper.RegisterOrLogError(logger, registerer, maxHistoricalSnapshotsRetained, "ocr3_1_config_max_historical_snapshots_retained") + + // blobs + deltaBlobOfferMinRequestToSameOracleInterval := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "ocr3_1_config_delta_blob_offer_min_request_to_same_oracle_interval_seconds", + Help: "See https://pkg.go.dev/github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config#PublicConfig for details", + }) + deltaBlobOfferMinRequestToSameOracleInterval.Set(publicConfig.GetDeltaBlobOfferMinRequestToSameOracleInterval().Seconds()) + metricshelper.RegisterOrLogError(logger, registerer, deltaBlobOfferMinRequestToSameOracleInterval, "ocr3_1_config_delta_blob_offer_min_request_to_same_oracle_interval_seconds") + + deltaBlobOfferResponseTimeout := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "ocr3_1_config_delta_blob_offer_response_timeout_seconds", + Help: "See https://pkg.go.dev/github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config#PublicConfig for details", + }) + deltaBlobOfferResponseTimeout.Set(publicConfig.GetDeltaBlobOfferResponseTimeout().Seconds()) + metricshelper.RegisterOrLogError(logger, registerer, deltaBlobOfferResponseTimeout, "ocr3_1_config_delta_blob_offer_response_timeout_seconds") + + deltaBlobBroadcastGrace := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "ocr3_1_config_delta_blob_broadcast_grace_seconds", + Help: "See https://pkg.go.dev/github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config#PublicConfig for details", + }) + deltaBlobBroadcastGrace.Set(publicConfig.GetDeltaBlobBroadcastGrace().Seconds()) + metricshelper.RegisterOrLogError(logger, registerer, deltaBlobBroadcastGrace, "ocr3_1_config_delta_blob_broadcast_grace_seconds") + + deltaBlobChunkMinRequestToSameOracleInterval := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "ocr3_1_config_delta_blob_chunk_min_request_to_same_oracle_interval_seconds", + Help: "See https://pkg.go.dev/github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config#PublicConfig for details", + }) + deltaBlobChunkMinRequestToSameOracleInterval.Set(publicConfig.GetDeltaBlobChunkMinRequestToSameOracleInterval().Seconds()) + metricshelper.RegisterOrLogError(logger, registerer, deltaBlobChunkMinRequestToSameOracleInterval, "ocr3_1_config_delta_blob_chunk_min_request_to_same_oracle_interval_seconds") + + deltaBlobChunkResponseTimeout := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "ocr3_1_config_delta_blob_chunk_response_timeout_seconds", + Help: "See https://pkg.go.dev/github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config#PublicConfig for details", + }) + deltaBlobChunkResponseTimeout.Set(publicConfig.GetDeltaBlobChunkResponseTimeout().Seconds()) + metricshelper.RegisterOrLogError(logger, registerer, deltaBlobChunkResponseTimeout, "ocr3_1_config_delta_blob_chunk_response_timeout_seconds") + + blobChunkBytes := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "ocr3_1_config_blob_chunk_bytes", + Help: "See https://pkg.go.dev/github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config#PublicConfig for details", + }) + blobChunkBytes.Set(float64(publicConfig.GetBlobChunkBytes())) + metricshelper.RegisterOrLogError(logger, registerer, blobChunkBytes, "ocr3_1_config_blob_chunk_bytes") + + rMax := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "ocr3_1_config_r_max", + Help: "See https://pkg.go.dev/github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config#PublicConfig for details", + }) + rMax.Set(float64(publicConfig.RMax)) + metricshelper.RegisterOrLogError(logger, registerer, rMax, "ocr3_1_config_r_max") + + maxDurationInitialization := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "ocr3_1_config_max_duration_initialization_seconds", + Help: "See https://pkg.go.dev/github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config#PublicConfig for details", + }) + maxDurationInitialization.Set(publicConfig.MaxDurationInitialization.Seconds()) + metricshelper.RegisterOrLogError(logger, registerer, maxDurationInitialization, "ocr3_1_config_max_duration_initialization_seconds") + + warnDurationQuery := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "ocr3_1_config_warn_duration_query_seconds", + Help: "See https://pkg.go.dev/github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config#PublicConfig for details", + }) + warnDurationQuery.Set(publicConfig.WarnDurationQuery.Seconds()) + metricshelper.RegisterOrLogError(logger, registerer, warnDurationQuery, "ocr3_1_config_warn_duration_query_seconds") + + warnDurationObservation := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "ocr3_1_config_warn_duration_observation_seconds", + Help: "See https://pkg.go.dev/github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config#PublicConfig for details", + }) + warnDurationObservation.Set(publicConfig.WarnDurationObservation.Seconds()) + metricshelper.RegisterOrLogError(logger, registerer, warnDurationObservation, "ocr3_1_config_warn_duration_observation_seconds") + + warnDurationValidateObservation := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "ocr3_1_config_warn_duration_validate_observation_seconds", + Help: "See https://pkg.go.dev/github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config#PublicConfig for details", + }) + warnDurationValidateObservation.Set(publicConfig.WarnDurationValidateObservation.Seconds()) + metricshelper.RegisterOrLogError(logger, registerer, warnDurationValidateObservation, "ocr3_1_config_warn_duration_validate_observation_seconds") + + warnDurationObservationQuorum := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "ocr3_1_config_warn_duration_observation_quorum_seconds", + Help: "See https://pkg.go.dev/github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config#PublicConfig for details", + }) + warnDurationObservationQuorum.Set(publicConfig.WarnDurationObservationQuorum.Seconds()) + metricshelper.RegisterOrLogError(logger, registerer, warnDurationObservationQuorum, "ocr3_1_config_warn_duration_observation_quorum_seconds") + + warnDurationStateTransition := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "ocr3_1_config_warn_duration_state_transition_seconds", + Help: "See https://pkg.go.dev/github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config#PublicConfig for details", + }) + warnDurationStateTransition.Set(publicConfig.WarnDurationStateTransition.Seconds()) + metricshelper.RegisterOrLogError(logger, registerer, warnDurationStateTransition, "ocr3_1_config_warn_duration_state_transition_seconds") + + warnDurationCommitted := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "ocr3_1_config_warn_duration_committed_seconds", + Help: "See https://pkg.go.dev/github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config#PublicConfig for details", + }) + warnDurationCommitted.Set(publicConfig.WarnDurationCommitted.Seconds()) + metricshelper.RegisterOrLogError(logger, registerer, warnDurationCommitted, "ocr3_1_config_warn_duration_committed_seconds") + + maxDurationShouldAcceptAttestedReport := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "ocr3_1_config_max_duration_should_accept_attested_report_seconds", + Help: "See https://pkg.go.dev/github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config#PublicConfig for details", + }) + maxDurationShouldAcceptAttestedReport.Set(publicConfig.MaxDurationShouldAcceptAttestedReport.Seconds()) + metricshelper.RegisterOrLogError(logger, registerer, maxDurationShouldAcceptAttestedReport, "ocr3_1_config_max_duration_should_accept_attested_report_seconds") + + maxDurationShouldTransmitAcceptedReport := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "ocr3_1_config_max_duration_should_transmit_accepted_report_seconds", + Help: "See https://pkg.go.dev/github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config#PublicConfig for details", + }) + maxDurationShouldTransmitAcceptedReport.Set(publicConfig.MaxDurationShouldTransmitAcceptedReport.Seconds()) + metricshelper.RegisterOrLogError(logger, registerer, maxDurationShouldTransmitAcceptedReport, "ocr3_1_config_max_duration_should_transmit_accepted_report_seconds") + + n := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "ocr3_1_config_n", + Help: "The number of oracles participating in this protocol instance", + }) + n.Set(float64(publicConfig.N())) + metricshelper.RegisterOrLogError(logger, registerer, n, "ocr3_1_config_n") + + f := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "ocr3_1_config_f", + Help: "The maximum number of oracles that are assumed to be faulty while the protocol can retain liveness and safety", + }) + f.Set(float64(publicConfig.F)) + metricshelper.RegisterOrLogError(logger, registerer, f, "ocr3_1_config_f") + + minRoundInterval := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "ocr3_1_config_min_round_interval_seconds", + Help: "See https://pkg.go.dev/github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config#PublicConfig for details", + }) + minRoundInterval.Set(publicConfig.MinRoundInterval().Seconds()) + metricshelper.RegisterOrLogError(logger, registerer, minRoundInterval, "ocr3_1_config_min_round_interval_seconds") + + return &PublicConfigMetrics{ + registerer, + + deltaProgress, + deltaResend, + deltaInitial, + deltaRound, + deltaGrace, + deltaReportsPlusPrecursorRequest, + deltaStage, + + // state sync + deltaStateSyncSummaryInterval, + + // block sync + deltaBlockSyncMinRequestToSameOracleInterval, + deltaBlockSyncResponseTimeout, + maxBlocksPerBlockSyncResponse, + maxParallelRequestedBlocks, + + // tree sync + deltaTreeSyncMinRequestToSameOracleInterval, + deltaTreeSyncResponseTimeout, + maxTreeSyncChunkKeys, + maxTreeSyncChunkKeysPlusValuesBytes, + maxParallelTreeSyncChunkFetches, + + // snapshotting + snapshotInterval, + maxHistoricalSnapshotsRetained, + + // blobs + deltaBlobOfferMinRequestToSameOracleInterval, + deltaBlobOfferResponseTimeout, + deltaBlobBroadcastGrace, + deltaBlobChunkMinRequestToSameOracleInterval, + deltaBlobChunkResponseTimeout, + blobChunkBytes, + + rMax, + + maxDurationInitialization, + warnDurationQuery, + warnDurationObservation, + warnDurationValidateObservation, + warnDurationObservationQuorum, + warnDurationStateTransition, + warnDurationCommitted, + maxDurationShouldAcceptAttestedReport, + maxDurationShouldTransmitAcceptedReport, + + n, + f, + minRoundInterval, + } +} + +func (pm *PublicConfigMetrics) Close() { + pm.registerer.Unregister(pm.deltaProgress) + pm.registerer.Unregister(pm.deltaResend) + pm.registerer.Unregister(pm.deltaInitial) + pm.registerer.Unregister(pm.deltaRound) + pm.registerer.Unregister(pm.deltaGrace) + pm.registerer.Unregister(pm.deltaReportsPlusPrecursorRequest) + pm.registerer.Unregister(pm.deltaStage) + + // state sync + pm.registerer.Unregister(pm.deltaStateSyncSummaryInterval) + + // block sync + pm.registerer.Unregister(pm.deltaBlockSyncMinRequestToSameOracleInterval) + pm.registerer.Unregister(pm.deltaBlockSyncResponseTimeout) + pm.registerer.Unregister(pm.maxBlocksPerBlockSyncResponse) + pm.registerer.Unregister(pm.maxParallelRequestedBlocks) + + // tree sync + pm.registerer.Unregister(pm.deltaTreeSyncMinRequestToSameOracleInterval) + pm.registerer.Unregister(pm.deltaTreeSyncResponseTimeout) + pm.registerer.Unregister(pm.maxTreeSyncChunkKeys) + pm.registerer.Unregister(pm.maxTreeSyncChunkKeysPlusValuesBytes) + pm.registerer.Unregister(pm.maxParallelTreeSyncChunkFetches) + + // snapshotting + pm.registerer.Unregister(pm.snapshotInterval) + pm.registerer.Unregister(pm.maxHistoricalSnapshotsRetained) + + // blobs + pm.registerer.Unregister(pm.deltaBlobOfferMinRequestToSameOracleInterval) + pm.registerer.Unregister(pm.deltaBlobOfferResponseTimeout) + pm.registerer.Unregister(pm.deltaBlobBroadcastGrace) + pm.registerer.Unregister(pm.deltaBlobChunkMinRequestToSameOracleInterval) + pm.registerer.Unregister(pm.deltaBlobChunkResponseTimeout) + pm.registerer.Unregister(pm.blobChunkBytes) + + pm.registerer.Unregister(pm.rMax) + + pm.registerer.Unregister(pm.maxDurationInitialization) + pm.registerer.Unregister(pm.warnDurationQuery) + pm.registerer.Unregister(pm.warnDurationObservation) + pm.registerer.Unregister(pm.warnDurationValidateObservation) + pm.registerer.Unregister(pm.warnDurationObservationQuorum) + pm.registerer.Unregister(pm.warnDurationStateTransition) + pm.registerer.Unregister(pm.warnDurationCommitted) + pm.registerer.Unregister(pm.maxDurationShouldAcceptAttestedReport) + pm.registerer.Unregister(pm.maxDurationShouldTransmitAcceptedReport) + + pm.registerer.Unregister(pm.n) + pm.registerer.Unregister(pm.f) + pm.registerer.Unregister(pm.minRoundInterval) +} diff --git a/offchainreporting2plus/internal/config/ocr3_1config/offchainreporting3_1_offchain_config.pb.go b/offchainreporting2plus/internal/config/ocr3_1config/offchainreporting3_1_offchain_config.pb.go new file mode 100644 index 00000000..bb7fb22a --- /dev/null +++ b/offchainreporting2plus/internal/config/ocr3_1config/offchainreporting3_1_offchain_config.pb.go @@ -0,0 +1,811 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.31.0 +// protoc v4.25.1 +// source: offchainreporting3_1_offchain_config.proto + +package ocr3_1config + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type OffchainConfigProto struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + DeltaProgressNanoseconds uint64 `protobuf:"varint,51,opt,name=delta_progress_nanoseconds,json=deltaProgressNanoseconds,proto3" json:"delta_progress_nanoseconds,omitempty"` + DeltaResendNanoseconds *uint64 `protobuf:"varint,52,opt,name=delta_resend_nanoseconds,json=deltaResendNanoseconds,proto3,oneof" json:"delta_resend_nanoseconds,omitempty"` + DeltaInitialNanoseconds *uint64 `protobuf:"varint,53,opt,name=delta_initial_nanoseconds,json=deltaInitialNanoseconds,proto3,oneof" json:"delta_initial_nanoseconds,omitempty"` + DeltaRoundNanoseconds uint64 `protobuf:"varint,54,opt,name=delta_round_nanoseconds,json=deltaRoundNanoseconds,proto3" json:"delta_round_nanoseconds,omitempty"` + DeltaGraceNanoseconds uint64 `protobuf:"varint,55,opt,name=delta_grace_nanoseconds,json=deltaGraceNanoseconds,proto3" json:"delta_grace_nanoseconds,omitempty"` + DeltaReportsPlusPrecursorRequestNanoseconds *uint64 `protobuf:"varint,56,opt,name=delta_reports_plus_precursor_request_nanoseconds,json=deltaReportsPlusPrecursorRequestNanoseconds,proto3,oneof" json:"delta_reports_plus_precursor_request_nanoseconds,omitempty"` + DeltaStageNanoseconds uint64 `protobuf:"varint,57,opt,name=delta_stage_nanoseconds,json=deltaStageNanoseconds,proto3" json:"delta_stage_nanoseconds,omitempty"` + DeltaStateSyncSummaryIntervalNanoseconds *uint64 `protobuf:"varint,58,opt,name=delta_state_sync_summary_interval_nanoseconds,json=deltaStateSyncSummaryIntervalNanoseconds,proto3,oneof" json:"delta_state_sync_summary_interval_nanoseconds,omitempty"` + DeltaBlockSyncMinRequestToSameOracleIntervalNanoseconds *uint64 `protobuf:"varint,59,opt,name=delta_block_sync_min_request_to_same_oracle_interval_nanoseconds,json=deltaBlockSyncMinRequestToSameOracleIntervalNanoseconds,proto3,oneof" json:"delta_block_sync_min_request_to_same_oracle_interval_nanoseconds,omitempty"` + DeltaBlockSyncResponseTimeoutNanoseconds *uint64 `protobuf:"varint,60,opt,name=delta_block_sync_response_timeout_nanoseconds,json=deltaBlockSyncResponseTimeoutNanoseconds,proto3,oneof" json:"delta_block_sync_response_timeout_nanoseconds,omitempty"` + MaxBlocksPerBlockSyncResponse *uint32 `protobuf:"varint,61,opt,name=max_blocks_per_block_sync_response,json=maxBlocksPerBlockSyncResponse,proto3,oneof" json:"max_blocks_per_block_sync_response,omitempty"` + MaxParallelRequestedBlocks *uint64 `protobuf:"varint,62,opt,name=max_parallel_requested_blocks,json=maxParallelRequestedBlocks,proto3,oneof" json:"max_parallel_requested_blocks,omitempty"` + DeltaTreeSyncMinRequestToSameOracleIntervalNanoseconds *uint64 `protobuf:"varint,63,opt,name=delta_tree_sync_min_request_to_same_oracle_interval_nanoseconds,json=deltaTreeSyncMinRequestToSameOracleIntervalNanoseconds,proto3,oneof" json:"delta_tree_sync_min_request_to_same_oracle_interval_nanoseconds,omitempty"` + DeltaTreeSyncResponseTimeoutNanoseconds *uint64 `protobuf:"varint,64,opt,name=delta_tree_sync_response_timeout_nanoseconds,json=deltaTreeSyncResponseTimeoutNanoseconds,proto3,oneof" json:"delta_tree_sync_response_timeout_nanoseconds,omitempty"` + MaxTreeSyncChunkKeys *uint32 `protobuf:"varint,65,opt,name=max_tree_sync_chunk_keys,json=maxTreeSyncChunkKeys,proto3,oneof" json:"max_tree_sync_chunk_keys,omitempty"` + MaxTreeSyncChunkKeysPlusValuesBytes *uint32 `protobuf:"varint,66,opt,name=max_tree_sync_chunk_keys_plus_values_bytes,json=maxTreeSyncChunkKeysPlusValuesBytes,proto3,oneof" json:"max_tree_sync_chunk_keys_plus_values_bytes,omitempty"` + MaxParallelTreeSyncChunkFetches *uint32 `protobuf:"varint,67,opt,name=max_parallel_tree_sync_chunk_fetches,json=maxParallelTreeSyncChunkFetches,proto3,oneof" json:"max_parallel_tree_sync_chunk_fetches,omitempty"` + SnapshotInterval *uint64 `protobuf:"varint,68,opt,name=snapshot_interval,json=snapshotInterval,proto3,oneof" json:"snapshot_interval,omitempty"` + MaxHistoricalSnapshotsRetained *uint64 `protobuf:"varint,69,opt,name=max_historical_snapshots_retained,json=maxHistoricalSnapshotsRetained,proto3,oneof" json:"max_historical_snapshots_retained,omitempty"` + DeltaBlobOfferMinRequestToSameOracleIntervalNanoseconds *uint64 `protobuf:"varint,70,opt,name=delta_blob_offer_min_request_to_same_oracle_interval_nanoseconds,json=deltaBlobOfferMinRequestToSameOracleIntervalNanoseconds,proto3,oneof" json:"delta_blob_offer_min_request_to_same_oracle_interval_nanoseconds,omitempty"` + DeltaBlobOfferResponseTimeoutNanoseconds *uint64 `protobuf:"varint,71,opt,name=delta_blob_offer_response_timeout_nanoseconds,json=deltaBlobOfferResponseTimeoutNanoseconds,proto3,oneof" json:"delta_blob_offer_response_timeout_nanoseconds,omitempty"` + DeltaBlobBroadcastGraceNanoseconds *uint64 `protobuf:"varint,72,opt,name=delta_blob_broadcast_grace_nanoseconds,json=deltaBlobBroadcastGraceNanoseconds,proto3,oneof" json:"delta_blob_broadcast_grace_nanoseconds,omitempty"` + DeltaBlobChunkMinRequestToSameOracleIntervalNanoseconds *uint64 `protobuf:"varint,73,opt,name=delta_blob_chunk_min_request_to_same_oracle_interval_nanoseconds,json=deltaBlobChunkMinRequestToSameOracleIntervalNanoseconds,proto3,oneof" json:"delta_blob_chunk_min_request_to_same_oracle_interval_nanoseconds,omitempty"` + DeltaBlobChunkResponseTimeoutNanoseconds *uint64 `protobuf:"varint,74,opt,name=delta_blob_chunk_response_timeout_nanoseconds,json=deltaBlobChunkResponseTimeoutNanoseconds,proto3,oneof" json:"delta_blob_chunk_response_timeout_nanoseconds,omitempty"` + BlobChunkBytes *uint32 `protobuf:"varint,75,opt,name=blob_chunk_bytes,json=blobChunkBytes,proto3,oneof" json:"blob_chunk_bytes,omitempty"` + RMax uint64 `protobuf:"varint,76,opt,name=r_max,json=rMax,proto3" json:"r_max,omitempty"` + S []uint32 `protobuf:"varint,77,rep,packed,name=s,proto3" json:"s,omitempty"` + OffchainPublicKeys [][]byte `protobuf:"bytes,78,rep,name=offchain_public_keys,json=offchainPublicKeys,proto3" json:"offchain_public_keys,omitempty"` + PeerIds []string `protobuf:"bytes,79,rep,name=peer_ids,json=peerIds,proto3" json:"peer_ids,omitempty"` + ReportingPluginConfig []byte `protobuf:"bytes,80,opt,name=reporting_plugin_config,json=reportingPluginConfig,proto3" json:"reporting_plugin_config,omitempty"` + MaxDurationInitializationNanoseconds uint64 `protobuf:"varint,81,opt,name=max_duration_initialization_nanoseconds,json=maxDurationInitializationNanoseconds,proto3" json:"max_duration_initialization_nanoseconds,omitempty"` + WarnDurationQueryNanoseconds uint64 `protobuf:"varint,82,opt,name=warn_duration_query_nanoseconds,json=warnDurationQueryNanoseconds,proto3" json:"warn_duration_query_nanoseconds,omitempty"` + WarnDurationObservationNanoseconds uint64 `protobuf:"varint,83,opt,name=warn_duration_observation_nanoseconds,json=warnDurationObservationNanoseconds,proto3" json:"warn_duration_observation_nanoseconds,omitempty"` + WarnDurationValidateObservationNanoseconds uint64 `protobuf:"varint,84,opt,name=warn_duration_validate_observation_nanoseconds,json=warnDurationValidateObservationNanoseconds,proto3" json:"warn_duration_validate_observation_nanoseconds,omitempty"` + WarnDurationObservationQuorumNanoseconds uint64 `protobuf:"varint,85,opt,name=warn_duration_observation_quorum_nanoseconds,json=warnDurationObservationQuorumNanoseconds,proto3" json:"warn_duration_observation_quorum_nanoseconds,omitempty"` + WarnDurationStateTransitionNanoseconds uint64 `protobuf:"varint,86,opt,name=warn_duration_state_transition_nanoseconds,json=warnDurationStateTransitionNanoseconds,proto3" json:"warn_duration_state_transition_nanoseconds,omitempty"` + WarnDurationCommittedNanoseconds uint64 `protobuf:"varint,87,opt,name=warn_duration_committed_nanoseconds,json=warnDurationCommittedNanoseconds,proto3" json:"warn_duration_committed_nanoseconds,omitempty"` + MaxDurationShouldAcceptAttestedReportNanoseconds uint64 `protobuf:"varint,88,opt,name=max_duration_should_accept_attested_report_nanoseconds,json=maxDurationShouldAcceptAttestedReportNanoseconds,proto3" json:"max_duration_should_accept_attested_report_nanoseconds,omitempty"` + MaxDurationShouldTransmitAcceptedReportNanoseconds uint64 `protobuf:"varint,89,opt,name=max_duration_should_transmit_accepted_report_nanoseconds,json=maxDurationShouldTransmitAcceptedReportNanoseconds,proto3" json:"max_duration_should_transmit_accepted_report_nanoseconds,omitempty"` + SharedSecretEncryptions *SharedSecretEncryptionsProto `protobuf:"bytes,90,opt,name=shared_secret_encryptions,json=sharedSecretEncryptions,proto3" json:"shared_secret_encryptions,omitempty"` +} + +func (x *OffchainConfigProto) Reset() { + *x = OffchainConfigProto{} + if protoimpl.UnsafeEnabled { + mi := &file_offchainreporting3_1_offchain_config_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *OffchainConfigProto) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*OffchainConfigProto) ProtoMessage() {} + +func (x *OffchainConfigProto) ProtoReflect() protoreflect.Message { + mi := &file_offchainreporting3_1_offchain_config_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use OffchainConfigProto.ProtoReflect.Descriptor instead. +func (*OffchainConfigProto) Descriptor() ([]byte, []int) { + return file_offchainreporting3_1_offchain_config_proto_rawDescGZIP(), []int{0} +} + +func (x *OffchainConfigProto) GetDeltaProgressNanoseconds() uint64 { + if x != nil { + return x.DeltaProgressNanoseconds + } + return 0 +} + +func (x *OffchainConfigProto) GetDeltaResendNanoseconds() uint64 { + if x != nil && x.DeltaResendNanoseconds != nil { + return *x.DeltaResendNanoseconds + } + return 0 +} + +func (x *OffchainConfigProto) GetDeltaInitialNanoseconds() uint64 { + if x != nil && x.DeltaInitialNanoseconds != nil { + return *x.DeltaInitialNanoseconds + } + return 0 +} + +func (x *OffchainConfigProto) GetDeltaRoundNanoseconds() uint64 { + if x != nil { + return x.DeltaRoundNanoseconds + } + return 0 +} + +func (x *OffchainConfigProto) GetDeltaGraceNanoseconds() uint64 { + if x != nil { + return x.DeltaGraceNanoseconds + } + return 0 +} + +func (x *OffchainConfigProto) GetDeltaReportsPlusPrecursorRequestNanoseconds() uint64 { + if x != nil && x.DeltaReportsPlusPrecursorRequestNanoseconds != nil { + return *x.DeltaReportsPlusPrecursorRequestNanoseconds + } + return 0 +} + +func (x *OffchainConfigProto) GetDeltaStageNanoseconds() uint64 { + if x != nil { + return x.DeltaStageNanoseconds + } + return 0 +} + +func (x *OffchainConfigProto) GetDeltaStateSyncSummaryIntervalNanoseconds() uint64 { + if x != nil && x.DeltaStateSyncSummaryIntervalNanoseconds != nil { + return *x.DeltaStateSyncSummaryIntervalNanoseconds + } + return 0 +} + +func (x *OffchainConfigProto) GetDeltaBlockSyncMinRequestToSameOracleIntervalNanoseconds() uint64 { + if x != nil && x.DeltaBlockSyncMinRequestToSameOracleIntervalNanoseconds != nil { + return *x.DeltaBlockSyncMinRequestToSameOracleIntervalNanoseconds + } + return 0 +} + +func (x *OffchainConfigProto) GetDeltaBlockSyncResponseTimeoutNanoseconds() uint64 { + if x != nil && x.DeltaBlockSyncResponseTimeoutNanoseconds != nil { + return *x.DeltaBlockSyncResponseTimeoutNanoseconds + } + return 0 +} + +func (x *OffchainConfigProto) GetMaxBlocksPerBlockSyncResponse() uint32 { + if x != nil && x.MaxBlocksPerBlockSyncResponse != nil { + return *x.MaxBlocksPerBlockSyncResponse + } + return 0 +} + +func (x *OffchainConfigProto) GetMaxParallelRequestedBlocks() uint64 { + if x != nil && x.MaxParallelRequestedBlocks != nil { + return *x.MaxParallelRequestedBlocks + } + return 0 +} + +func (x *OffchainConfigProto) GetDeltaTreeSyncMinRequestToSameOracleIntervalNanoseconds() uint64 { + if x != nil && x.DeltaTreeSyncMinRequestToSameOracleIntervalNanoseconds != nil { + return *x.DeltaTreeSyncMinRequestToSameOracleIntervalNanoseconds + } + return 0 +} + +func (x *OffchainConfigProto) GetDeltaTreeSyncResponseTimeoutNanoseconds() uint64 { + if x != nil && x.DeltaTreeSyncResponseTimeoutNanoseconds != nil { + return *x.DeltaTreeSyncResponseTimeoutNanoseconds + } + return 0 +} + +func (x *OffchainConfigProto) GetMaxTreeSyncChunkKeys() uint32 { + if x != nil && x.MaxTreeSyncChunkKeys != nil { + return *x.MaxTreeSyncChunkKeys + } + return 0 +} + +func (x *OffchainConfigProto) GetMaxTreeSyncChunkKeysPlusValuesBytes() uint32 { + if x != nil && x.MaxTreeSyncChunkKeysPlusValuesBytes != nil { + return *x.MaxTreeSyncChunkKeysPlusValuesBytes + } + return 0 +} + +func (x *OffchainConfigProto) GetMaxParallelTreeSyncChunkFetches() uint32 { + if x != nil && x.MaxParallelTreeSyncChunkFetches != nil { + return *x.MaxParallelTreeSyncChunkFetches + } + return 0 +} + +func (x *OffchainConfigProto) GetSnapshotInterval() uint64 { + if x != nil && x.SnapshotInterval != nil { + return *x.SnapshotInterval + } + return 0 +} + +func (x *OffchainConfigProto) GetMaxHistoricalSnapshotsRetained() uint64 { + if x != nil && x.MaxHistoricalSnapshotsRetained != nil { + return *x.MaxHistoricalSnapshotsRetained + } + return 0 +} + +func (x *OffchainConfigProto) GetDeltaBlobOfferMinRequestToSameOracleIntervalNanoseconds() uint64 { + if x != nil && x.DeltaBlobOfferMinRequestToSameOracleIntervalNanoseconds != nil { + return *x.DeltaBlobOfferMinRequestToSameOracleIntervalNanoseconds + } + return 0 +} + +func (x *OffchainConfigProto) GetDeltaBlobOfferResponseTimeoutNanoseconds() uint64 { + if x != nil && x.DeltaBlobOfferResponseTimeoutNanoseconds != nil { + return *x.DeltaBlobOfferResponseTimeoutNanoseconds + } + return 0 +} + +func (x *OffchainConfigProto) GetDeltaBlobBroadcastGraceNanoseconds() uint64 { + if x != nil && x.DeltaBlobBroadcastGraceNanoseconds != nil { + return *x.DeltaBlobBroadcastGraceNanoseconds + } + return 0 +} + +func (x *OffchainConfigProto) GetDeltaBlobChunkMinRequestToSameOracleIntervalNanoseconds() uint64 { + if x != nil && x.DeltaBlobChunkMinRequestToSameOracleIntervalNanoseconds != nil { + return *x.DeltaBlobChunkMinRequestToSameOracleIntervalNanoseconds + } + return 0 +} + +func (x *OffchainConfigProto) GetDeltaBlobChunkResponseTimeoutNanoseconds() uint64 { + if x != nil && x.DeltaBlobChunkResponseTimeoutNanoseconds != nil { + return *x.DeltaBlobChunkResponseTimeoutNanoseconds + } + return 0 +} + +func (x *OffchainConfigProto) GetBlobChunkBytes() uint32 { + if x != nil && x.BlobChunkBytes != nil { + return *x.BlobChunkBytes + } + return 0 +} + +func (x *OffchainConfigProto) GetRMax() uint64 { + if x != nil { + return x.RMax + } + return 0 +} + +func (x *OffchainConfigProto) GetS() []uint32 { + if x != nil { + return x.S + } + return nil +} + +func (x *OffchainConfigProto) GetOffchainPublicKeys() [][]byte { + if x != nil { + return x.OffchainPublicKeys + } + return nil +} + +func (x *OffchainConfigProto) GetPeerIds() []string { + if x != nil { + return x.PeerIds + } + return nil +} + +func (x *OffchainConfigProto) GetReportingPluginConfig() []byte { + if x != nil { + return x.ReportingPluginConfig + } + return nil +} + +func (x *OffchainConfigProto) GetMaxDurationInitializationNanoseconds() uint64 { + if x != nil { + return x.MaxDurationInitializationNanoseconds + } + return 0 +} + +func (x *OffchainConfigProto) GetWarnDurationQueryNanoseconds() uint64 { + if x != nil { + return x.WarnDurationQueryNanoseconds + } + return 0 +} + +func (x *OffchainConfigProto) GetWarnDurationObservationNanoseconds() uint64 { + if x != nil { + return x.WarnDurationObservationNanoseconds + } + return 0 +} + +func (x *OffchainConfigProto) GetWarnDurationValidateObservationNanoseconds() uint64 { + if x != nil { + return x.WarnDurationValidateObservationNanoseconds + } + return 0 +} + +func (x *OffchainConfigProto) GetWarnDurationObservationQuorumNanoseconds() uint64 { + if x != nil { + return x.WarnDurationObservationQuorumNanoseconds + } + return 0 +} + +func (x *OffchainConfigProto) GetWarnDurationStateTransitionNanoseconds() uint64 { + if x != nil { + return x.WarnDurationStateTransitionNanoseconds + } + return 0 +} + +func (x *OffchainConfigProto) GetWarnDurationCommittedNanoseconds() uint64 { + if x != nil { + return x.WarnDurationCommittedNanoseconds + } + return 0 +} + +func (x *OffchainConfigProto) GetMaxDurationShouldAcceptAttestedReportNanoseconds() uint64 { + if x != nil { + return x.MaxDurationShouldAcceptAttestedReportNanoseconds + } + return 0 +} + +func (x *OffchainConfigProto) GetMaxDurationShouldTransmitAcceptedReportNanoseconds() uint64 { + if x != nil { + return x.MaxDurationShouldTransmitAcceptedReportNanoseconds + } + return 0 +} + +func (x *OffchainConfigProto) GetSharedSecretEncryptions() *SharedSecretEncryptionsProto { + if x != nil { + return x.SharedSecretEncryptions + } + return nil +} + +type SharedSecretEncryptionsProto struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + DiffieHellmanPoint []byte `protobuf:"bytes,1,opt,name=diffieHellmanPoint,proto3" json:"diffieHellmanPoint,omitempty"` + SharedSecretHash []byte `protobuf:"bytes,2,opt,name=sharedSecretHash,proto3" json:"sharedSecretHash,omitempty"` + Encryptions [][]byte `protobuf:"bytes,3,rep,name=encryptions,proto3" json:"encryptions,omitempty"` +} + +func (x *SharedSecretEncryptionsProto) Reset() { + *x = SharedSecretEncryptionsProto{} + if protoimpl.UnsafeEnabled { + mi := &file_offchainreporting3_1_offchain_config_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SharedSecretEncryptionsProto) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SharedSecretEncryptionsProto) ProtoMessage() {} + +func (x *SharedSecretEncryptionsProto) ProtoReflect() protoreflect.Message { + mi := &file_offchainreporting3_1_offchain_config_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SharedSecretEncryptionsProto.ProtoReflect.Descriptor instead. +func (*SharedSecretEncryptionsProto) Descriptor() ([]byte, []int) { + return file_offchainreporting3_1_offchain_config_proto_rawDescGZIP(), []int{1} +} + +func (x *SharedSecretEncryptionsProto) GetDiffieHellmanPoint() []byte { + if x != nil { + return x.DiffieHellmanPoint + } + return nil +} + +func (x *SharedSecretEncryptionsProto) GetSharedSecretHash() []byte { + if x != nil { + return x.SharedSecretHash + } + return nil +} + +func (x *SharedSecretEncryptionsProto) GetEncryptions() [][]byte { + if x != nil { + return x.Encryptions + } + return nil +} + +var File_offchainreporting3_1_offchain_config_proto protoreflect.FileDescriptor + +var file_offchainreporting3_1_offchain_config_proto_rawDesc = []byte{ + 0x0a, 0x2a, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, + 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x5f, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1b, 0x6f, 0x66, + 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, + 0x5f, 0x31, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0xbf, 0x21, 0x0a, 0x13, 0x4f, 0x66, + 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x50, 0x72, 0x6f, 0x74, + 0x6f, 0x12, 0x3c, 0x0a, 0x1a, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x5f, 0x70, 0x72, 0x6f, 0x67, 0x72, + 0x65, 0x73, 0x73, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, + 0x33, 0x20, 0x01, 0x28, 0x04, 0x52, 0x18, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x50, 0x72, 0x6f, 0x67, + 0x72, 0x65, 0x73, 0x73, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x12, + 0x3d, 0x0a, 0x18, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x5f, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x64, 0x5f, + 0x6e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x34, 0x20, 0x01, 0x28, + 0x04, 0x48, 0x00, 0x52, 0x16, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x52, 0x65, 0x73, 0x65, 0x6e, 0x64, + 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x88, 0x01, 0x01, 0x12, 0x3f, + 0x0a, 0x19, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x5f, + 0x6e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x35, 0x20, 0x01, 0x28, + 0x04, 0x48, 0x01, 0x52, 0x17, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, + 0x6c, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x88, 0x01, 0x01, 0x12, + 0x36, 0x0a, 0x17, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x5f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x6e, + 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x36, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x15, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x4e, 0x61, 0x6e, 0x6f, + 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x12, 0x36, 0x0a, 0x17, 0x64, 0x65, 0x6c, 0x74, 0x61, + 0x5f, 0x67, 0x72, 0x61, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, + 0x64, 0x73, 0x18, 0x37, 0x20, 0x01, 0x28, 0x04, 0x52, 0x15, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x47, + 0x72, 0x61, 0x63, 0x65, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x12, + 0x6a, 0x0a, 0x30, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x5f, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x73, + 0x5f, 0x70, 0x6c, 0x75, 0x73, 0x5f, 0x70, 0x72, 0x65, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x5f, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, + 0x6e, 0x64, 0x73, 0x18, 0x38, 0x20, 0x01, 0x28, 0x04, 0x48, 0x02, 0x52, 0x2b, 0x64, 0x65, 0x6c, + 0x74, 0x61, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x50, 0x6c, 0x75, 0x73, 0x50, 0x72, 0x65, + 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4e, 0x61, 0x6e, + 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x88, 0x01, 0x01, 0x12, 0x36, 0x0a, 0x17, 0x64, + 0x65, 0x6c, 0x74, 0x61, 0x5f, 0x73, 0x74, 0x61, 0x67, 0x65, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x73, + 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x39, 0x20, 0x01, 0x28, 0x04, 0x52, 0x15, 0x64, 0x65, + 0x6c, 0x74, 0x61, 0x53, 0x74, 0x61, 0x67, 0x65, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, + 0x6e, 0x64, 0x73, 0x12, 0x64, 0x0a, 0x2d, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x5f, 0x73, 0x74, 0x61, + 0x74, 0x65, 0x5f, 0x73, 0x79, 0x6e, 0x63, 0x5f, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x5f, + 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, + 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x3a, 0x20, 0x01, 0x28, 0x04, 0x48, 0x03, 0x52, 0x28, 0x64, 0x65, + 0x6c, 0x74, 0x61, 0x53, 0x74, 0x61, 0x74, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x53, 0x75, 0x6d, 0x6d, + 0x61, 0x72, 0x79, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x4e, 0x61, 0x6e, 0x6f, 0x73, + 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x88, 0x01, 0x01, 0x12, 0x86, 0x01, 0x0a, 0x40, 0x64, 0x65, + 0x6c, 0x74, 0x61, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x73, 0x79, 0x6e, 0x63, 0x5f, 0x6d, + 0x69, 0x6e, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x74, 0x6f, 0x5f, 0x73, 0x61, + 0x6d, 0x65, 0x5f, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, + 0x61, 0x6c, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x3b, + 0x20, 0x01, 0x28, 0x04, 0x48, 0x04, 0x52, 0x37, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x54, 0x6f, 0x53, 0x61, 0x6d, 0x65, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x49, 0x6e, 0x74, 0x65, + 0x72, 0x76, 0x61, 0x6c, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x88, + 0x01, 0x01, 0x12, 0x64, 0x0a, 0x2d, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x5f, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x5f, 0x73, 0x79, 0x6e, 0x63, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, + 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, + 0x6e, 0x64, 0x73, 0x18, 0x3c, 0x20, 0x01, 0x28, 0x04, 0x48, 0x05, 0x52, 0x28, 0x64, 0x65, 0x6c, + 0x74, 0x61, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x65, + 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x88, 0x01, 0x01, 0x12, 0x4e, 0x0a, 0x22, 0x6d, 0x61, 0x78, 0x5f, + 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x5f, 0x73, 0x79, 0x6e, 0x63, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x3d, + 0x20, 0x01, 0x28, 0x0d, 0x48, 0x06, 0x52, 0x1d, 0x6d, 0x61, 0x78, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x73, 0x50, 0x65, 0x72, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x88, 0x01, 0x01, 0x12, 0x46, 0x0a, 0x1d, 0x6d, 0x61, 0x78, 0x5f, + 0x70, 0x61, 0x72, 0x61, 0x6c, 0x6c, 0x65, 0x6c, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x65, 0x64, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x3e, 0x20, 0x01, 0x28, 0x04, 0x48, + 0x07, 0x52, 0x1a, 0x6d, 0x61, 0x78, 0x50, 0x61, 0x72, 0x61, 0x6c, 0x6c, 0x65, 0x6c, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x65, 0x64, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x88, 0x01, 0x01, + 0x12, 0x84, 0x01, 0x0a, 0x3f, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x5f, 0x74, 0x72, 0x65, 0x65, 0x5f, + 0x73, 0x79, 0x6e, 0x63, 0x5f, 0x6d, 0x69, 0x6e, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x5f, 0x74, 0x6f, 0x5f, 0x73, 0x61, 0x6d, 0x65, 0x5f, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, + 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, + 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x3f, 0x20, 0x01, 0x28, 0x04, 0x48, 0x08, 0x52, 0x36, 0x64, 0x65, + 0x6c, 0x74, 0x61, 0x54, 0x72, 0x65, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x69, 0x6e, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x6f, 0x53, 0x61, 0x6d, 0x65, 0x4f, 0x72, 0x61, 0x63, 0x6c, + 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, + 0x6f, 0x6e, 0x64, 0x73, 0x88, 0x01, 0x01, 0x12, 0x62, 0x0a, 0x2c, 0x64, 0x65, 0x6c, 0x74, 0x61, + 0x5f, 0x74, 0x72, 0x65, 0x65, 0x5f, 0x73, 0x79, 0x6e, 0x63, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, + 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x40, 0x20, 0x01, 0x28, 0x04, 0x48, 0x09, 0x52, + 0x27, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x54, 0x72, 0x65, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x4e, 0x61, 0x6e, + 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x88, 0x01, 0x01, 0x12, 0x3b, 0x0a, 0x18, 0x6d, + 0x61, 0x78, 0x5f, 0x74, 0x72, 0x65, 0x65, 0x5f, 0x73, 0x79, 0x6e, 0x63, 0x5f, 0x63, 0x68, 0x75, + 0x6e, 0x6b, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x41, 0x20, 0x01, 0x28, 0x0d, 0x48, 0x0a, 0x52, + 0x14, 0x6d, 0x61, 0x78, 0x54, 0x72, 0x65, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x43, 0x68, 0x75, 0x6e, + 0x6b, 0x4b, 0x65, 0x79, 0x73, 0x88, 0x01, 0x01, 0x12, 0x5c, 0x0a, 0x2a, 0x6d, 0x61, 0x78, 0x5f, + 0x74, 0x72, 0x65, 0x65, 0x5f, 0x73, 0x79, 0x6e, 0x63, 0x5f, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x5f, + 0x6b, 0x65, 0x79, 0x73, 0x5f, 0x70, 0x6c, 0x75, 0x73, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, + 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x42, 0x20, 0x01, 0x28, 0x0d, 0x48, 0x0b, 0x52, 0x23, + 0x6d, 0x61, 0x78, 0x54, 0x72, 0x65, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x43, 0x68, 0x75, 0x6e, 0x6b, + 0x4b, 0x65, 0x79, 0x73, 0x50, 0x6c, 0x75, 0x73, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x42, 0x79, + 0x74, 0x65, 0x73, 0x88, 0x01, 0x01, 0x12, 0x52, 0x0a, 0x24, 0x6d, 0x61, 0x78, 0x5f, 0x70, 0x61, + 0x72, 0x61, 0x6c, 0x6c, 0x65, 0x6c, 0x5f, 0x74, 0x72, 0x65, 0x65, 0x5f, 0x73, 0x79, 0x6e, 0x63, + 0x5f, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x5f, 0x66, 0x65, 0x74, 0x63, 0x68, 0x65, 0x73, 0x18, 0x43, + 0x20, 0x01, 0x28, 0x0d, 0x48, 0x0c, 0x52, 0x1f, 0x6d, 0x61, 0x78, 0x50, 0x61, 0x72, 0x61, 0x6c, + 0x6c, 0x65, 0x6c, 0x54, 0x72, 0x65, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x43, 0x68, 0x75, 0x6e, 0x6b, + 0x46, 0x65, 0x74, 0x63, 0x68, 0x65, 0x73, 0x88, 0x01, 0x01, 0x12, 0x30, 0x0a, 0x11, 0x73, 0x6e, + 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, + 0x44, 0x20, 0x01, 0x28, 0x04, 0x48, 0x0d, 0x52, 0x10, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, + 0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x88, 0x01, 0x01, 0x12, 0x4e, 0x0a, 0x21, + 0x6d, 0x61, 0x78, 0x5f, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x73, + 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x5f, 0x72, 0x65, 0x74, 0x61, 0x69, 0x6e, 0x65, + 0x64, 0x18, 0x45, 0x20, 0x01, 0x28, 0x04, 0x48, 0x0e, 0x52, 0x1e, 0x6d, 0x61, 0x78, 0x48, 0x69, + 0x73, 0x74, 0x6f, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, + 0x73, 0x52, 0x65, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x64, 0x88, 0x01, 0x01, 0x12, 0x86, 0x01, 0x0a, + 0x40, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x5f, 0x62, 0x6c, 0x6f, 0x62, 0x5f, 0x6f, 0x66, 0x66, 0x65, + 0x72, 0x5f, 0x6d, 0x69, 0x6e, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x74, 0x6f, + 0x5f, 0x73, 0x61, 0x6d, 0x65, 0x5f, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x69, 0x6e, 0x74, + 0x65, 0x72, 0x76, 0x61, 0x6c, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, + 0x73, 0x18, 0x46, 0x20, 0x01, 0x28, 0x04, 0x48, 0x0f, 0x52, 0x37, 0x64, 0x65, 0x6c, 0x74, 0x61, + 0x42, 0x6c, 0x6f, 0x62, 0x4f, 0x66, 0x66, 0x65, 0x72, 0x4d, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x54, 0x6f, 0x53, 0x61, 0x6d, 0x65, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x49, + 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, + 0x64, 0x73, 0x88, 0x01, 0x01, 0x12, 0x64, 0x0a, 0x2d, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x5f, 0x62, + 0x6c, 0x6f, 0x62, 0x5f, 0x6f, 0x66, 0x66, 0x65, 0x72, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x73, + 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x47, 0x20, 0x01, 0x28, 0x04, 0x48, 0x10, 0x52, 0x28, + 0x64, 0x65, 0x6c, 0x74, 0x61, 0x42, 0x6c, 0x6f, 0x62, 0x4f, 0x66, 0x66, 0x65, 0x72, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x4e, 0x61, 0x6e, + 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x88, 0x01, 0x01, 0x12, 0x57, 0x0a, 0x26, 0x64, + 0x65, 0x6c, 0x74, 0x61, 0x5f, 0x62, 0x6c, 0x6f, 0x62, 0x5f, 0x62, 0x72, 0x6f, 0x61, 0x64, 0x63, + 0x61, 0x73, 0x74, 0x5f, 0x67, 0x72, 0x61, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x73, 0x65, + 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x48, 0x20, 0x01, 0x28, 0x04, 0x48, 0x11, 0x52, 0x22, 0x64, + 0x65, 0x6c, 0x74, 0x61, 0x42, 0x6c, 0x6f, 0x62, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, + 0x74, 0x47, 0x72, 0x61, 0x63, 0x65, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, + 0x73, 0x88, 0x01, 0x01, 0x12, 0x86, 0x01, 0x0a, 0x40, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x5f, 0x62, + 0x6c, 0x6f, 0x62, 0x5f, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x5f, 0x6d, 0x69, 0x6e, 0x5f, 0x72, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x74, 0x6f, 0x5f, 0x73, 0x61, 0x6d, 0x65, 0x5f, 0x6f, 0x72, + 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x5f, 0x6e, 0x61, + 0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x49, 0x20, 0x01, 0x28, 0x04, 0x48, + 0x12, 0x52, 0x37, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x42, 0x6c, 0x6f, 0x62, 0x43, 0x68, 0x75, 0x6e, + 0x6b, 0x4d, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x6f, 0x53, 0x61, 0x6d, + 0x65, 0x4f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x4e, + 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x88, 0x01, 0x01, 0x12, 0x64, 0x0a, + 0x2d, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x5f, 0x62, 0x6c, 0x6f, 0x62, 0x5f, 0x63, 0x68, 0x75, 0x6e, + 0x6b, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, + 0x75, 0x74, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x4a, + 0x20, 0x01, 0x28, 0x04, 0x48, 0x13, 0x52, 0x28, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x42, 0x6c, 0x6f, + 0x62, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x54, 0x69, + 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, + 0x88, 0x01, 0x01, 0x12, 0x2d, 0x0a, 0x10, 0x62, 0x6c, 0x6f, 0x62, 0x5f, 0x63, 0x68, 0x75, 0x6e, + 0x6b, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x4b, 0x20, 0x01, 0x28, 0x0d, 0x48, 0x14, 0x52, + 0x0e, 0x62, 0x6c, 0x6f, 0x62, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x42, 0x79, 0x74, 0x65, 0x73, 0x88, + 0x01, 0x01, 0x12, 0x13, 0x0a, 0x05, 0x72, 0x5f, 0x6d, 0x61, 0x78, 0x18, 0x4c, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x04, 0x72, 0x4d, 0x61, 0x78, 0x12, 0x0c, 0x0a, 0x01, 0x73, 0x18, 0x4d, 0x20, 0x03, + 0x28, 0x0d, 0x52, 0x01, 0x73, 0x12, 0x30, 0x0a, 0x14, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, + 0x6e, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x4e, 0x20, + 0x03, 0x28, 0x0c, 0x52, 0x12, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x50, 0x75, 0x62, + 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x70, 0x65, 0x65, 0x72, 0x5f, + 0x69, 0x64, 0x73, 0x18, 0x4f, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x70, 0x65, 0x65, 0x72, 0x49, + 0x64, 0x73, 0x12, 0x36, 0x0a, 0x17, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x5f, + 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x50, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x15, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x50, 0x6c, + 0x75, 0x67, 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x55, 0x0a, 0x27, 0x6d, 0x61, + 0x78, 0x5f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x69, + 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x73, 0x65, + 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x51, 0x20, 0x01, 0x28, 0x04, 0x52, 0x24, 0x6d, 0x61, 0x78, + 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x69, + 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, + 0x73, 0x12, 0x45, 0x0a, 0x1f, 0x77, 0x61, 0x72, 0x6e, 0x5f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, + 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x52, 0x20, 0x01, 0x28, 0x04, 0x52, 0x1c, 0x77, 0x61, 0x72, 0x6e, + 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4e, 0x61, 0x6e, + 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x12, 0x51, 0x0a, 0x25, 0x77, 0x61, 0x72, 0x6e, + 0x5f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, + 0x73, 0x18, 0x53, 0x20, 0x01, 0x28, 0x04, 0x52, 0x22, 0x77, 0x61, 0x72, 0x6e, 0x44, 0x75, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x12, 0x62, 0x0a, 0x2e, 0x77, + 0x61, 0x72, 0x6e, 0x5f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x76, 0x61, 0x6c, + 0x69, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x54, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x2a, 0x77, 0x61, 0x72, 0x6e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x12, + 0x5e, 0x0a, 0x2c, 0x77, 0x61, 0x72, 0x6e, 0x5f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x71, 0x75, 0x6f, + 0x72, 0x75, 0x6d, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, + 0x55, 0x20, 0x01, 0x28, 0x04, 0x52, 0x28, 0x77, 0x61, 0x72, 0x6e, 0x44, 0x75, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x51, 0x75, + 0x6f, 0x72, 0x75, 0x6d, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x12, + 0x5a, 0x0a, 0x2a, 0x77, 0x61, 0x72, 0x6e, 0x5f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x56, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x26, 0x77, 0x61, 0x72, 0x6e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x12, 0x4d, 0x0a, 0x23, 0x77, + 0x61, 0x72, 0x6e, 0x5f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x6d, + 0x6d, 0x69, 0x74, 0x74, 0x65, 0x64, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, + 0x64, 0x73, 0x18, 0x57, 0x20, 0x01, 0x28, 0x04, 0x52, 0x20, 0x77, 0x61, 0x72, 0x6e, 0x44, 0x75, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x64, 0x4e, + 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x12, 0x70, 0x0a, 0x36, 0x6d, 0x61, + 0x78, 0x5f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x68, 0x6f, 0x75, 0x6c, + 0x64, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x5f, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, + 0x64, 0x5f, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, + 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x58, 0x20, 0x01, 0x28, 0x04, 0x52, 0x30, 0x6d, 0x61, 0x78, 0x44, + 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x41, 0x63, 0x63, + 0x65, 0x70, 0x74, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x52, 0x65, 0x70, 0x6f, 0x72, + 0x74, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x12, 0x74, 0x0a, 0x38, + 0x6d, 0x61, 0x78, 0x5f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x68, 0x6f, + 0x75, 0x6c, 0x64, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x6d, 0x69, 0x74, 0x5f, 0x61, 0x63, 0x63, + 0x65, 0x70, 0x74, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x6e, 0x61, 0x6e, + 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x59, 0x20, 0x01, 0x28, 0x04, 0x52, 0x32, + 0x6d, 0x61, 0x78, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x68, 0x6f, 0x75, 0x6c, + 0x64, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x6d, 0x69, 0x74, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, + 0x64, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, + 0x64, 0x73, 0x12, 0x75, 0x0a, 0x19, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5f, 0x73, 0x65, 0x63, + 0x72, 0x65, 0x74, 0x5f, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, + 0x5a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, + 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x5f, 0x63, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x2e, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, + 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, + 0x52, 0x17, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x45, 0x6e, + 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x42, 0x1b, 0x0a, 0x19, 0x5f, 0x64, 0x65, + 0x6c, 0x74, 0x61, 0x5f, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x64, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x73, + 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x42, 0x1c, 0x0a, 0x1a, 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61, + 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, + 0x6f, 0x6e, 0x64, 0x73, 0x42, 0x33, 0x0a, 0x31, 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x5f, 0x72, + 0x65, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x5f, 0x70, 0x6c, 0x75, 0x73, 0x5f, 0x70, 0x72, 0x65, 0x63, + 0x75, 0x72, 0x73, 0x6f, 0x72, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x6e, 0x61, + 0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x42, 0x30, 0x0a, 0x2e, 0x5f, 0x64, 0x65, + 0x6c, 0x74, 0x61, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x79, 0x6e, 0x63, 0x5f, 0x73, + 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x5f, + 0x6e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x42, 0x43, 0x0a, 0x41, 0x5f, + 0x64, 0x65, 0x6c, 0x74, 0x61, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x73, 0x79, 0x6e, 0x63, + 0x5f, 0x6d, 0x69, 0x6e, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x74, 0x6f, 0x5f, + 0x73, 0x61, 0x6d, 0x65, 0x5f, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x69, 0x6e, 0x74, 0x65, + 0x72, 0x76, 0x61, 0x6c, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, + 0x42, 0x30, 0x0a, 0x2e, 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x5f, 0x73, 0x79, 0x6e, 0x63, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x74, + 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, + 0x64, 0x73, 0x42, 0x25, 0x0a, 0x23, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x73, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x73, 0x79, 0x6e, 0x63, + 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x20, 0x0a, 0x1e, 0x5f, 0x6d, 0x61, + 0x78, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6c, 0x6c, 0x65, 0x6c, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x65, 0x64, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x42, 0x42, 0x0a, 0x40, 0x5f, + 0x64, 0x65, 0x6c, 0x74, 0x61, 0x5f, 0x74, 0x72, 0x65, 0x65, 0x5f, 0x73, 0x79, 0x6e, 0x63, 0x5f, + 0x6d, 0x69, 0x6e, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x74, 0x6f, 0x5f, 0x73, + 0x61, 0x6d, 0x65, 0x5f, 0x6f, 0x72, 0x61, 0x63, 0x6c, 0x65, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x76, 0x61, 0x6c, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x42, + 0x2f, 0x0a, 0x2d, 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x5f, 0x74, 0x72, 0x65, 0x65, 0x5f, 0x73, + 0x79, 0x6e, 0x63, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x74, 0x69, 0x6d, + 0x65, 0x6f, 0x75, 0x74, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, + 0x42, 0x1b, 0x0a, 0x19, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x74, 0x72, 0x65, 0x65, 0x5f, 0x73, 0x79, + 0x6e, 0x63, 0x5f, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x42, 0x2d, 0x0a, + 0x2b, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x74, 0x72, 0x65, 0x65, 0x5f, 0x73, 0x79, 0x6e, 0x63, 0x5f, + 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x5f, 0x70, 0x6c, 0x75, 0x73, 0x5f, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x42, 0x27, 0x0a, 0x25, + 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6c, 0x6c, 0x65, 0x6c, 0x5f, 0x74, 0x72, + 0x65, 0x65, 0x5f, 0x73, 0x79, 0x6e, 0x63, 0x5f, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x5f, 0x66, 0x65, + 0x74, 0x63, 0x68, 0x65, 0x73, 0x42, 0x14, 0x0a, 0x12, 0x5f, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, + 0x6f, 0x74, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x42, 0x24, 0x0a, 0x22, 0x5f, + 0x6d, 0x61, 0x78, 0x5f, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x73, + 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x5f, 0x72, 0x65, 0x74, 0x61, 0x69, 0x6e, 0x65, + 0x64, 0x42, 0x43, 0x0a, 0x41, 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x5f, 0x62, 0x6c, 0x6f, 0x62, + 0x5f, 0x6f, 0x66, 0x66, 0x65, 0x72, 0x5f, 0x6d, 0x69, 0x6e, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x5f, 0x74, 0x6f, 0x5f, 0x73, 0x61, 0x6d, 0x65, 0x5f, 0x6f, 0x72, 0x61, 0x63, 0x6c, + 0x65, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x73, + 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x42, 0x30, 0x0a, 0x2e, 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61, + 0x5f, 0x62, 0x6c, 0x6f, 0x62, 0x5f, 0x6f, 0x66, 0x66, 0x65, 0x72, 0x5f, 0x72, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x5f, 0x6e, 0x61, 0x6e, + 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x42, 0x29, 0x0a, 0x27, 0x5f, 0x64, 0x65, 0x6c, + 0x74, 0x61, 0x5f, 0x62, 0x6c, 0x6f, 0x62, 0x5f, 0x62, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, + 0x74, 0x5f, 0x67, 0x72, 0x61, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, + 0x6e, 0x64, 0x73, 0x42, 0x43, 0x0a, 0x41, 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x5f, 0x62, 0x6c, + 0x6f, 0x62, 0x5f, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x5f, 0x6d, 0x69, 0x6e, 0x5f, 0x72, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x5f, 0x74, 0x6f, 0x5f, 0x73, 0x61, 0x6d, 0x65, 0x5f, 0x6f, 0x72, 0x61, + 0x63, 0x6c, 0x65, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x5f, 0x6e, 0x61, 0x6e, + 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x42, 0x30, 0x0a, 0x2e, 0x5f, 0x64, 0x65, 0x6c, + 0x74, 0x61, 0x5f, 0x62, 0x6c, 0x6f, 0x62, 0x5f, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x5f, 0x72, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x5f, 0x6e, + 0x61, 0x6e, 0x6f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x62, + 0x6c, 0x6f, 0x62, 0x5f, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x4a, + 0x04, 0x08, 0x01, 0x10, 0x2b, 0x4a, 0x04, 0x08, 0x2b, 0x10, 0x33, 0x22, 0x9c, 0x01, 0x0a, 0x1c, + 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x45, 0x6e, 0x63, 0x72, + 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x2e, 0x0a, 0x12, + 0x64, 0x69, 0x66, 0x66, 0x69, 0x65, 0x48, 0x65, 0x6c, 0x6c, 0x6d, 0x61, 0x6e, 0x50, 0x6f, 0x69, + 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x12, 0x64, 0x69, 0x66, 0x66, 0x69, 0x65, + 0x48, 0x65, 0x6c, 0x6c, 0x6d, 0x61, 0x6e, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x2a, 0x0a, 0x10, + 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x48, 0x61, 0x73, 0x68, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x53, 0x65, + 0x63, 0x72, 0x65, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x20, 0x0a, 0x0b, 0x65, 0x6e, 0x63, 0x72, + 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0b, 0x65, + 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x42, 0x10, 0x5a, 0x0e, 0x2e, 0x3b, + 0x6f, 0x63, 0x72, 0x33, 0x5f, 0x31, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_offchainreporting3_1_offchain_config_proto_rawDescOnce sync.Once + file_offchainreporting3_1_offchain_config_proto_rawDescData = file_offchainreporting3_1_offchain_config_proto_rawDesc +) + +func file_offchainreporting3_1_offchain_config_proto_rawDescGZIP() []byte { + file_offchainreporting3_1_offchain_config_proto_rawDescOnce.Do(func() { + file_offchainreporting3_1_offchain_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_offchainreporting3_1_offchain_config_proto_rawDescData) + }) + return file_offchainreporting3_1_offchain_config_proto_rawDescData +} + +var file_offchainreporting3_1_offchain_config_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_offchainreporting3_1_offchain_config_proto_goTypes = []interface{}{ + (*OffchainConfigProto)(nil), // 0: offchainreporting3_1_config.OffchainConfigProto + (*SharedSecretEncryptionsProto)(nil), // 1: offchainreporting3_1_config.SharedSecretEncryptionsProto +} +var file_offchainreporting3_1_offchain_config_proto_depIdxs = []int32{ + 1, // 0: offchainreporting3_1_config.OffchainConfigProto.shared_secret_encryptions:type_name -> offchainreporting3_1_config.SharedSecretEncryptionsProto + 1, // [1:1] is the sub-list for method output_type + 1, // [1:1] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name +} + +func init() { file_offchainreporting3_1_offchain_config_proto_init() } +func file_offchainreporting3_1_offchain_config_proto_init() { + if File_offchainreporting3_1_offchain_config_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_offchainreporting3_1_offchain_config_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*OffchainConfigProto); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_offchainreporting3_1_offchain_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SharedSecretEncryptionsProto); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_offchainreporting3_1_offchain_config_proto_msgTypes[0].OneofWrappers = []interface{}{} + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_offchainreporting3_1_offchain_config_proto_rawDesc, + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_offchainreporting3_1_offchain_config_proto_goTypes, + DependencyIndexes: file_offchainreporting3_1_offchain_config_proto_depIdxs, + MessageInfos: file_offchainreporting3_1_offchain_config_proto_msgTypes, + }.Build() + File_offchainreporting3_1_offchain_config_proto = out.File + file_offchainreporting3_1_offchain_config_proto_rawDesc = nil + file_offchainreporting3_1_offchain_config_proto_goTypes = nil + file_offchainreporting3_1_offchain_config_proto_depIdxs = nil +} diff --git a/offchainreporting2plus/internal/config/ocr3_1config/public_config.go b/offchainreporting2plus/internal/config/ocr3_1config/public_config.go new file mode 100644 index 00000000..7b63929d --- /dev/null +++ b/offchainreporting2plus/internal/config/ocr3_1config/public_config.go @@ -0,0 +1,845 @@ +package ocr3_1config + +import ( + "bytes" + "fmt" + "math" + "math/big" + "strconv" + "time" + + "github.com/pkg/errors" + "github.com/smartcontractkit/libocr/internal/byzquorum" + "github.com/smartcontractkit/libocr/internal/util" + "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config" + "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3_1types" + "github.com/smartcontractkit/libocr/offchainreporting2plus/types" +) + +// PublicConfig is the configuration disseminated through the smart contract. +// It's public, because anybody can read it from the blockchain. +// The various parameters (e.g. Delta*, MaxDuration*) have some dependencies +// on each other, so be sure to consider the holistic impact of changes to them. +type PublicConfig struct { + // If an epoch (driven by a leader) fails to achieve progress (generate a + // report) after DeltaProgress, we enter a new epoch. This parameter must be + // chosen carefully. If the duration is too short, we may keep prematurely + // switching epochs without ever achieving any progress, resulting in a + // liveness failure! + DeltaProgress time.Duration + // DeltaResend determines how often Pacemaker messages should be + // resent, allowing oracles that had crashed and are recovering to rejoin + // the protocol more quickly. + DeltaResend *time.Duration + // If no message from the leader has been received after the epoch start plus + // DeltaInitial, we enter a new epoch. This parameter must be + // chosen carefully. If the duration is too short, we may keep prematurely + // switching epochs without ever achieving any progress, resulting in a + // liveness failure! + DeltaInitial *time.Duration + // DeltaRound determines the minimal amount of time that should pass between + // the start of outcome generation rounds. With OCR3 and higher versions (not OCR1!) + // you can set this value very aggressively. Note that this only provides a lower + // bound on the round interval; actual rounds might take longer. + DeltaRound time.Duration + // Once the leader of a outcome generation round has collected sufficiently + // many observations, it will wait for DeltaGrace to pass to allow slower + // oracles to still contribute an observation before moving on to generating + // the report. Consequently, rounds driven by correct leaders will always + // take at least DeltaGrace. + DeltaGrace time.Duration + // DeltaReportsPlusPrecursorRequest determines the duration between requests for + // reports plus precursor after we have received f+1 signatures in the report + // attestation protocol but are still missing the reports plus precursor + // required for validating the report signatures. + DeltaReportsPlusPrecursorRequest *time.Duration + // DeltaStage determines the duration between stages of the transmission + // protocol. In each stage, a certain number of oracles (determined by S) + // will attempt to transmit, assuming that no other oracle has yet + // successfully transmitted a report. + DeltaStage time.Duration + + // === State Synchronization === + + // DeltaStateSyncSummaryInterval defines how frequently an oracle + // broadcasts a summary of its current state for synchronization purposes. + DeltaStateSyncSummaryInterval *time.Duration + + // === Block Synchronization === + + // DeltaBlockSyncMinRequestToSameOracleInterval specifies the minimum + // duration between two consecutive block synchronization requests + // sent to the same oracle. + DeltaBlockSyncMinRequestToSameOracleInterval *time.Duration + // DeltaBlockSyncResponseTimeout specifies the maximum time to wait + // for a response to a specific block synchronization request. + // If no response is received within this duration, + // the protocol retries with another oracle. + DeltaBlockSyncResponseTimeout *time.Duration + // MaxBlocksPerBlockSyncResponse defines the maximum number of blocks + // that can be included in a single block synchronization response. + MaxBlocksPerBlockSyncResponse *int + // MaxParallelRequestedBlocks upper bounds the number of blocks being + // requested in parallel. Multiple blocks might be fetched as part of a one + // request. + MaxParallelRequestedBlocks *uint64 + + // === Tree Synchronization === + + // DeltaTreeSyncMinRequestToSameOracleInterval specifies the minimum + // duration between two consecutive requests for tree synchronization + // sent to the same oracle. + DeltaTreeSyncMinRequestToSameOracleInterval *time.Duration + // DeltaTreeSyncResponseTimeout specifies the maximum amount of time to + // wait for a response to a specific tree synchronization request. + // If no response is received within this duration, + // the protocol retries with another oracle. + DeltaTreeSyncResponseTimeout *time.Duration + // MaxTreeSyncChunkKeys defines the maximum number of key-value pairs + // that an oracle includes in a single tree synchronization response chunk. + MaxTreeSyncChunkKeys *int + // MaxTreeSyncChunkKeysPlusValuesBytes defines the maximum combined + // size (in bytes) of all keys and values in a single tree + // synchronization response chunk. + // The protocol ensures that each chunk includes as many key-value pairs + // as possible without exceeding either this byte-size limit or + // MaxTreeSyncChunkKeys. + // A chunk must always fit at least one maximally sized (using maxmax) + // key-value pair. + MaxTreeSyncChunkKeysPlusValuesBytes *int + // MaxParallelTreeSyncChunkFetches defines the maximum number of tree + // synchronization requests that can be performed in parallel. + MaxParallelTreeSyncChunkFetches *int + + // === Snapshotting === + // SnapshotInterval is defined such that the committed sequence number of + // any snapshot must be a multiple of SnapshotInterval. Decreasing this + // value increases the max historical snapshots retained. + SnapshotInterval *uint64 + // MaxHistoricalSnapshotsRetained defines how many complete historical + // snapshots are retained. Retained snapshots enable other oracles to + // synchronize against the committed state from previous snapshot sequence + // numbers. All blocks from the highest block of the earliest retained + // snapshot onward will be kept available for synchronization purposes. + MaxHistoricalSnapshotsRetained *uint64 + + // === Blob Synchronization === + // + // DeltaBlobOfferMinRequestToSameOracleInterval defines the minimum + // duration between two consecutive blob offer requests sent to the same + // oracle. + DeltaBlobOfferMinRequestToSameOracleInterval *time.Duration + // DeltaBlobOfferResponseTimeout specifies the maximum duration to wait + // for a response to a blob offer before resending the blob offer. + DeltaBlobOfferResponseTimeout *time.Duration + // DeltaBlobBroadcastGrace defines the additional grace period to wait + // after receiving the minimum number of accepting blob offer responses. + // This allows more oracles a final opportunity to be included in the + // availability certificate. + DeltaBlobBroadcastGrace *time.Duration + // DeltaBlobChunkMinRequestToSameOracleInterval defines the minimum + // duration between two consecutive blob chunk requests sent to the same + // oracle. + DeltaBlobChunkMinRequestToSameOracleInterval *time.Duration + // DeltaBlobChunkResponseTimeout specifies the maximum duration to wait + // for a blob chunk response. If no response is received within this + // time, the protocol retries with another oracle. + DeltaBlobChunkResponseTimeout *time.Duration + // BlobChunkBytes defines the size of blob chunks in bytes. + BlobChunkBytes *int + + // The maximum number of rounds during an epoch. + RMax uint64 + // S is the transmission schedule. For example, S = [1,2,3] indicates that + // in the first stage of transmission one oracle will attempt to transmit, + // in the second stage two more will attempt to transmit (if in their view + // the first stage didn't succeed), and in the third stage three more will + // attempt to transmit (if in their view the first and second stage didn't + // succeed). + // + // sum(S) should equal n. + S []int + // Identities (i.e. public keys) of the oracles participating in this + // protocol instance. + OracleIdentities []config.OracleIdentity + + // Binary blob containing configuration passed through to the + // ReportingPlugin. + ReportingPluginConfig []byte + + // MaxDurationX is the maximum duration a ReportingPlugin should spend + // performing X. Reasonable values for these will be specific to each + // ReportingPlugin. Be sure to not set these too short, or the corresponding + // ReportingPlugin function may always time out. The logic for + // WarnDurationQuery and WarnDurationObservation has changed since these + // values were first introduced. Unlike the other MaxDurationX values, + // exceeding WarnDurationQuery and WarnDurationObservation will only cause + // warnings to be logged, but will *not* cause X to time out. + // + // These values are passed to the ReportingPlugin during initialization. + // Consequently, the ReportingPlugin may exhibit specific behaviors based on + // these values. For instance, the MercuryReportingPlugin uses + // WarnDurationObservation to set context timeouts. + MaxDurationInitialization time.Duration // Context deadline passed to NewReportingPlugin. + WarnDurationQuery time.Duration // If the Query function takes longer than this, a warning will be logged. + WarnDurationObservation time.Duration // If the Observation function takes longer than this, a warning will be logged. + WarnDurationValidateObservation time.Duration // If the ValidateObservation function takes longer than this, a warning will be logged. + WarnDurationObservationQuorum time.Duration // If the ObservationQuorum function takes longer than this, a warning will be logged. + WarnDurationStateTransition time.Duration // If the StateTransition function takes longer than this, a warning will be logged. + WarnDurationCommitted time.Duration // If the Committed function takes longer than this, a warning will be logged. + MaxDurationShouldAcceptAttestedReport time.Duration // Context deadline passed to ShouldAcceptAttestedReport. + MaxDurationShouldTransmitAcceptedReport time.Duration // Context deadline passed to ShouldTransmitAcceptedReport. + + // The maximum number of oracles that are assumed to be faulty while the + // protocol can retain liveness and safety. Unless you really know what + // you’re doing, be sure to set this to floor((n-1)/3) where n is the total + // number of oracles. + F int + + // Binary blob containing configuration passed through to the + // ReportingPlugin, and also available to the contract. (Unlike + // ReportingPluginConfig which is only available offchain.) + OnchainConfig []byte + + ConfigDigest types.ConfigDigest +} + +// N is the number of oracles participating in the protocol +func (c *PublicConfig) N() int { + return len(c.OracleIdentities) +} + +func (c *PublicConfig) ByzQuorumSize() int { + return byzquorum.Size(c.N(), c.F) +} + +func (c *PublicConfig) GetDeltaResend() time.Duration { + return util.NilCoalesce(c.DeltaResend, DefaultDeltaResend) +} + +func (c *PublicConfig) GetDeltaInitial() time.Duration { + return util.NilCoalesce(c.DeltaInitial, DefaultDeltaInitial()) +} + +func (c *PublicConfig) GetDeltaReportsPlusPrecursorRequest() time.Duration { + return util.NilCoalesce(c.DeltaReportsPlusPrecursorRequest, DefaultDeltaReportsPlusPrecursorRequest()) +} + +func (c *PublicConfig) GetDeltaStateSyncSummaryInterval() time.Duration { + return util.NilCoalesce(c.DeltaStateSyncSummaryInterval, DefaultDeltaStateSyncSummaryInterval) +} + +func (c *PublicConfig) GetDeltaBlockSyncMinRequestToSameOracleInterval() time.Duration { + return util.NilCoalesce(c.DeltaBlockSyncMinRequestToSameOracleInterval, DefaultDeltaBlockSyncMinRequestToSameOracleInterval) +} + +func (c *PublicConfig) GetDeltaBlockSyncResponseTimeout() time.Duration { + return util.NilCoalesce(c.DeltaBlockSyncResponseTimeout, DefaultDeltaBlockSyncResponseTimeout()) +} + +func (c *PublicConfig) GetMaxBlocksPerBlockSyncResponse() int { + return util.NilCoalesce(c.MaxBlocksPerBlockSyncResponse, DefaultMaxBlocksPerBlockSyncResponse) +} + +func (c *PublicConfig) GetMaxParallelRequestedBlocks() uint64 { + return util.NilCoalesce(c.MaxParallelRequestedBlocks, DefaultMaxParallelRequestedBlocks) +} + +func (c *PublicConfig) GetDeltaTreeSyncMinRequestToSameOracleInterval() time.Duration { + return util.NilCoalesce(c.DeltaTreeSyncMinRequestToSameOracleInterval, DefaultDeltaTreeSyncMinRequestToSameOracleInterval) +} + +func (c *PublicConfig) GetDeltaTreeSyncResponseTimeout() time.Duration { + return util.NilCoalesce(c.DeltaTreeSyncResponseTimeout, DefaultDeltaTreeSyncResponseTimeout()) +} + +func (c *PublicConfig) GetMaxTreeSyncChunkKeys() int { + return util.NilCoalesce(c.MaxTreeSyncChunkKeys, DefaultMaxTreeSyncChunkKeys) +} + +func (c *PublicConfig) GetMaxTreeSyncChunkKeysPlusValuesBytes() int { + return util.NilCoalesce(c.MaxTreeSyncChunkKeysPlusValuesBytes, DefaultMaxTreeSyncChunkKeysPlusValuesBytes) +} + +func (c *PublicConfig) GetMaxParallelTreeSyncChunkFetches() int { + return util.NilCoalesce(c.MaxParallelTreeSyncChunkFetches, DefaultMaxParallelTreeSyncChunkFetches) +} + +func (c *PublicConfig) GetSnapshotInterval() uint64 { + return util.NilCoalesce(c.SnapshotInterval, DefaultSnapshotInterval) +} + +func (c *PublicConfig) GetMaxHistoricalSnapshotsRetained() uint64 { + return util.NilCoalesce(c.MaxHistoricalSnapshotsRetained, DefaultMaxHistoricalSnapshotsRetained) +} + +func (c *PublicConfig) GetDeltaBlobOfferMinRequestToSameOracleInterval() time.Duration { + return util.NilCoalesce(c.DeltaBlobOfferMinRequestToSameOracleInterval, DefaultDeltaBlobOfferMinRequestToSameOracleInterval) +} + +func (c *PublicConfig) GetDeltaBlobOfferResponseTimeout() time.Duration { + return util.NilCoalesce(c.DeltaBlobOfferResponseTimeout, DefaultDeltaBlobOfferResponseTimeout) +} + +func (c *PublicConfig) GetDeltaBlobBroadcastGrace() time.Duration { + return util.NilCoalesce(c.DeltaBlobBroadcastGrace, DefaultDeltaBlobBroadcastGrace) +} + +func (c *PublicConfig) GetDeltaBlobChunkMinRequestToSameOracleInterval() time.Duration { + return util.NilCoalesce(c.DeltaBlobChunkMinRequestToSameOracleInterval, DefaultDeltaBlobChunkMinRequestToSameOracleInterval) +} + +func (c *PublicConfig) GetDeltaBlobChunkResponseTimeout() time.Duration { + return util.NilCoalesce(c.DeltaBlobChunkResponseTimeout, DefaultDeltaBlobChunkResponseTimeout()) +} + +func (c *PublicConfig) GetBlobChunkBytes() int { + return util.NilCoalesce(c.BlobChunkBytes, DefaultBlobChunkBytes) +} + +// The minimum interval between round starts. +// This is not a guaranteed lower bound. For example, a malicious leader could +// violate this bound. +func (c *PublicConfig) MinRoundInterval() time.Duration { + if c.DeltaRound > c.DeltaGrace { + return c.DeltaRound + } + return c.DeltaGrace +} + +func (c *PublicConfig) CheckParameterBounds() error { + if c.F < 0 || c.F > math.MaxUint8 { + return errors.Errorf("number of potentially faulty oracles must fit in 8 bits.") + } + return nil +} + +func PublicConfigFromContractConfig(skipInsaneForProductionChecks bool, change types.ContractConfig) (PublicConfig, error) { + pubcon, _, err := publicConfigFromContractConfig(skipInsaneForProductionChecks, change) + return pubcon, err +} + +func publicConfigFromContractConfig(skipInsaneForProductionChecks bool, change types.ContractConfig) (PublicConfig, config.SharedSecretEncryptions, error) { + if change.OffchainConfigVersion != config.OCR3_1OffchainConfigVersion { + return PublicConfig{}, config.SharedSecretEncryptions{}, fmt.Errorf("unsuppported OffchainConfigVersion %v, supported OffchainConfigVersion is %v", change.OffchainConfigVersion, config.OCR3_1OffchainConfigVersion) + } + + oc, err := deserializeOffchainConfig(change.OffchainConfig) + if err != nil { + return PublicConfig{}, config.SharedSecretEncryptions{}, err + } + + if err := checkIdentityListsHaveNoDuplicates(change, oc); err != nil { + return PublicConfig{}, config.SharedSecretEncryptions{}, err + } + + // must check that all lists have the same length, or bad input could crash + // the following for loop. + if err := checkIdentityListsHaveTheSameLength(change, oc); err != nil { + return PublicConfig{}, config.SharedSecretEncryptions{}, err + } + + identities := []config.OracleIdentity{} + for i := range change.Signers { + identities = append(identities, config.OracleIdentity{ + oc.OffchainPublicKeys[i], + types.OnchainPublicKey(change.Signers[i][:]), + oc.PeerIDs[i], + change.Transmitters[i], + }) + } + + cfg := PublicConfig{ + oc.DeltaProgress, + oc.DeltaResend, + oc.DeltaInitial, + oc.DeltaRound, + oc.DeltaGrace, + oc.DeltaReportsPlusPrecursorRequest, + oc.DeltaStage, + + // state sync + oc.DeltaStateSyncSummaryInterval, + + // block sync + oc.DeltaBlockSyncMinRequestToSameOracleInterval, + oc.DeltaBlockSyncResponseTimeout, + oc.MaxBlocksPerBlockSyncResponse, + oc.MaxParallelRequestedBlocks, + + // tree sync + oc.DeltaTreeSyncMinRequestToSameOracleInterval, + oc.DeltaTreeSyncResponseTimeout, + oc.MaxTreeSyncChunkKeys, + oc.MaxTreeSyncChunkKeysPlusValuesBytes, + oc.MaxParallelTreeSyncChunkFetches, + + // snapshotting + oc.SnapshotInterval, + oc.MaxHistoricalSnapshotsRetained, + + // blobs + oc.DeltaBlobOfferMinRequestToSameOracleInterval, + oc.DeltaBlobOfferResponseTimeout, + oc.DeltaBlobBroadcastGrace, + oc.DeltaBlobChunkMinRequestToSameOracleInterval, + oc.DeltaBlobChunkResponseTimeout, + oc.BlobChunkBytes, + + oc.RMax, + oc.S, + identities, + oc.ReportingPluginConfig, + oc.MaxDurationInitialization, + oc.WarnDurationQuery, + oc.WarnDurationObservation, + oc.WarnDurationValidateObservation, + oc.WarnDurationObservationQuorum, + oc.WarnDurationStateTransition, + oc.WarnDurationCommitted, + oc.MaxDurationShouldAcceptAttestedReport, + oc.MaxDurationShouldTransmitAcceptedReport, + + int(change.F), + change.OnchainConfig, + change.ConfigDigest, + } + + if err := CheckPublicConfig(skipInsaneForProductionChecks, cfg); err != nil { + return PublicConfig{}, config.SharedSecretEncryptions{}, err + } + + return cfg, oc.SharedSecretEncryptions, nil +} + +func CheckPublicConfig(skipInsaneForProductionChecks bool, publicConfig PublicConfig) error { + if err := checkPublicConfigParameters(publicConfig); err != nil { + return fmt.Errorf("checkPublicConfigParameters: %w", err) + } + + if err := checkIdentityListsHaveNoDuplicatesPublicConfig(publicConfig); err != nil { + return fmt.Errorf("checkIdentityListsHaveNoDuplicatesPublicConfig: %w", err) + } + + if !skipInsaneForProductionChecks { + if err := checkNotInsaneForProduction(publicConfig); err != nil { + return fmt.Errorf("checkNotInsaneForProduction: %w", err) + } + } + return nil +} + +func checkIdentityListsHaveNoDuplicates(change types.ContractConfig, oc offchainConfig) error { + // inefficient, but it doesn't matter + for i := range change.Signers { + for j := range change.Signers { + if i != j && bytes.Equal(change.Signers[i], change.Signers[j]) { + return fmt.Errorf("%v-th and %v-th signer are identical: %x", i, j, change.Signers[i]) + } + } + } + + { + uniquePeerIDs := map[string]struct{}{} + for _, peerID := range oc.PeerIDs { + if _, ok := uniquePeerIDs[peerID]; ok { + return fmt.Errorf("duplicate PeerID '%v'", peerID) + } + uniquePeerIDs[peerID] = struct{}{} + } + } + + { + uniqueOffchainPublicKeys := map[types.OffchainPublicKey]struct{}{} + for _, ocpk := range oc.OffchainPublicKeys { + if _, ok := uniqueOffchainPublicKeys[ocpk]; ok { + return fmt.Errorf("duplicate OffchainPublicKey %x", ocpk) + } + uniqueOffchainPublicKeys[ocpk] = struct{}{} + } + } + + { + // this isn't strictly necessary, but since we don't intend to run + // with duplicate transmitters at this time, we might as well check + uniqueTransmitters := map[types.Account]struct{}{} + for _, transmitter := range change.Transmitters { + if _, ok := uniqueTransmitters[transmitter]; ok { + return fmt.Errorf("duplicate transmitter '%v'", transmitter) + } + uniqueTransmitters[transmitter] = struct{}{} + } + } + + // no point in checking SharedSecretEncryptions for uniqueness + + return nil +} + +func checkIdentityListsHaveNoDuplicatesPublicConfig(publicConfig PublicConfig) error { + // inefficient, but it doesn't matter + for i := range publicConfig.OracleIdentities { + for j := range publicConfig.OracleIdentities { + if i != j && bytes.Equal(publicConfig.OracleIdentities[i].OnchainPublicKey, publicConfig.OracleIdentities[j].OnchainPublicKey) { + return fmt.Errorf("%v-th and %v-th OnchainPublicKey are identical: %x", i, j, publicConfig.OracleIdentities[i].OnchainPublicKey) + } + } + } + + { + uniquePeerIDs := map[string]struct{}{} + for _, oid := range publicConfig.OracleIdentities { + if _, ok := uniquePeerIDs[oid.PeerID]; ok { + return fmt.Errorf("duplicate PeerID '%v'", oid.PeerID) + } + uniquePeerIDs[oid.PeerID] = struct{}{} + } + } + + { + uniqueOffchainPublicKeys := map[types.OffchainPublicKey]struct{}{} + for _, oid := range publicConfig.OracleIdentities { + if _, ok := uniqueOffchainPublicKeys[oid.OffchainPublicKey]; ok { + return fmt.Errorf("duplicate OffchainPublicKey %x", oid.OffchainPublicKey) + } + uniqueOffchainPublicKeys[oid.OffchainPublicKey] = struct{}{} + } + } + + { + // this isn't strictly necessary, but since we don't intend to run + // with duplicate transmitters at this time, we might as well check + uniqueTransmitters := map[types.Account]struct{}{} + for _, oid := range publicConfig.OracleIdentities { + if _, ok := uniqueTransmitters[oid.TransmitAccount]; ok { + return fmt.Errorf("duplicate TransmitAccount '%v'", oid.TransmitAccount) + } + uniqueTransmitters[oid.TransmitAccount] = struct{}{} + } + } + + return nil +} + +func checkIdentityListsHaveTheSameLength( + change types.ContractConfig, oc offchainConfig, +) error { + expectedLength := len(change.Signers) + errorMsg := "%s list must have same length as onchain signers list: %d ≠ " + + strconv.Itoa(expectedLength) + for _, identityList := range []struct { + length int + name string + }{ + {len(oc.PeerIDs) /* */, "peer ids"}, + {len(oc.OffchainPublicKeys) /* */, "offchain public keys"}, + {len(change.Transmitters) /* */, "transmitters"}, + {len(oc.SharedSecretEncryptions.Encryptions), "shared-secret encryptions"}, + } { + if identityList.length != expectedLength { + return errors.Errorf(errorMsg, identityList.name, identityList.length) + } + } + return nil +} + +// Sanity check on parameters: +// (1) violations of fundamental constraints like 3*f= 0) { + return fmt.Errorf("SnapshotInterval (%v) * MaxHistoricalSnapshotsRetained (%v) * MinRoundInterval (%v) must be greater than or equal to 1 hour", cfg.GetSnapshotInterval(), cfg.GetMaxHistoricalSnapshotsRetained(), cfg.MinRoundInterval()) + } + sevenDaysNs := new(big.Int).SetInt64(int64(7 * 24 * time.Hour)) + if !(prodNs.Cmp(sevenDaysNs) <= 0) { + return fmt.Errorf("SnapshotInterval (%v) * MaxHistoricalSnapshotsRetained (%v) * MinRoundInterval (%v) must be less than or equal to 7 days", cfg.GetSnapshotInterval(), cfg.GetMaxHistoricalSnapshotsRetained(), cfg.MinRoundInterval()) + } + } + const maxMaxHistoricalSnapshotsRetained = 1_000 + if !(cfg.GetMaxHistoricalSnapshotsRetained() <= maxMaxHistoricalSnapshotsRetained) { + return fmt.Errorf("MaxHistoricalSnapshotsRetained (%v) must be less than or equal to %v", cfg.GetMaxHistoricalSnapshotsRetained(), maxMaxHistoricalSnapshotsRetained) + } + + if !(safeInterval <= cfg.GetDeltaStateSyncSummaryInterval()) { + return fmt.Errorf("DeltaStateSyncSummaryInterval (%v) is set below the resource exhaustion safe interval (%v)", cfg.GetDeltaStateSyncSummaryInterval(), safeInterval) + } + const safeRequestInterval = 10 * time.Millisecond + // request intervals + if !(safeRequestInterval <= cfg.GetDeltaReportsPlusPrecursorRequest()) { + return fmt.Errorf("DeltaReportsPlusPrecursorRequest (%v) is set below the safe request interval (%v)", cfg.GetDeltaReportsPlusPrecursorRequest(), safeRequestInterval) + } + if !(safeRequestInterval <= cfg.GetDeltaBlockSyncMinRequestToSameOracleInterval()) { + return fmt.Errorf("DeltaBlockSyncMinRequestToSameOracleInterval (%v) is set below the safe request interval (%v)", cfg.GetDeltaBlockSyncMinRequestToSameOracleInterval(), safeRequestInterval) + } + if !(safeRequestInterval <= cfg.GetDeltaTreeSyncMinRequestToSameOracleInterval()) { + return fmt.Errorf("DeltaTreeSyncMinRequestToSameOracleInterval (%v) is set below the safe request interval (%v)", cfg.GetDeltaTreeSyncMinRequestToSameOracleInterval(), safeRequestInterval) + } + if !(safeRequestInterval <= cfg.GetDeltaBlobChunkMinRequestToSameOracleInterval()) { + return fmt.Errorf("DeltaBlobChunkMinRequestToSameOracleInterval (%v) is set below the safe request interval (%v)", cfg.GetDeltaBlobChunkMinRequestToSameOracleInterval(), safeRequestInterval) + } + + // response timeouts + if !(safeInterval <= cfg.GetDeltaBlockSyncResponseTimeout()) { + return fmt.Errorf("DeltaBlockSyncResponseTimeout (%v) is set below the resource exhaustion safe interval (%v)", cfg.GetDeltaBlockSyncResponseTimeout(), safeInterval) + } + if !(safeInterval <= cfg.GetDeltaTreeSyncResponseTimeout()) { + return fmt.Errorf("DeltaTreeSyncResponseTimeout (%v) is set below the resource exhaustion safe interval (%v)", cfg.GetDeltaTreeSyncResponseTimeout(), safeInterval) + } + if !(safeInterval <= cfg.GetDeltaBlobChunkResponseTimeout()) { + return fmt.Errorf("DeltaBlobChunkResponseTimeout (%v) is set below the resource exhaustion safe interval (%v)", cfg.GetDeltaBlobChunkResponseTimeout(), safeInterval) + } + + if !(cfg.GetMaxBlocksPerBlockSyncResponse() <= MaxMaxBlocksPerBlockSyncResponse) { + return fmt.Errorf("MaxBlocksPerBlockSyncResponse (%v) must be less than or equal to %v", cfg.GetMaxBlocksPerBlockSyncResponse(), MaxMaxBlocksPerBlockSyncResponse) + } + if !(cfg.GetMaxTreeSyncChunkKeys() <= MaxMaxTreeSyncChunkKeys) { + return fmt.Errorf("MaxTreeSyncChunkKeys (%v) must be less than or equal to %v", cfg.GetMaxTreeSyncChunkKeys(), MaxMaxTreeSyncChunkKeys) + } + if !(cfg.GetMaxTreeSyncChunkKeysPlusValuesBytes() <= MaxMaxTreeSyncChunkKeysPlusValuesBytes) { + return fmt.Errorf("MaxTreeSyncChunkKeysPlusValuesBytes (%v) must be less than or equal to %v", cfg.GetMaxTreeSyncChunkKeysPlusValuesBytes(), MaxMaxTreeSyncChunkKeysPlusValuesBytes) + } + + // MaxParallelTreeSyncChunkFetches is already upper bounded in protocol code. + + if !(cfg.GetBlobChunkBytes() <= MaxMaxBlobChunkBytes) { + return fmt.Errorf("BlobChunkBytes (%v) must be less than or equal to %v", cfg.GetBlobChunkBytes(), MaxMaxBlobChunkBytes) + } + + const ( + minMaxDurationPluginCall = 10 * time.Millisecond + maxMaxDurationPluginCall = 10 * time.Minute + ) + if !(minMaxDurationPluginCall <= cfg.MaxDurationInitialization) { + return fmt.Errorf("MaxDurationInitialization (%v) must be greater than or equal to %v", cfg.MaxDurationInitialization, minMaxDurationPluginCall) + } + if !(cfg.MaxDurationInitialization <= maxMaxDurationPluginCall) { + return fmt.Errorf("MaxDurationInitialization (%v) must be less than or equal to %v", cfg.MaxDurationInitialization, maxMaxDurationPluginCall) + } + if !(minMaxDurationPluginCall <= cfg.MaxDurationShouldAcceptAttestedReport) { + return fmt.Errorf("MaxDurationShouldAcceptAttestedReport (%v) must be greater than or equal to %v", cfg.MaxDurationShouldAcceptAttestedReport, minMaxDurationPluginCall) + } + if !(cfg.MaxDurationShouldAcceptAttestedReport <= maxMaxDurationPluginCall) { + return fmt.Errorf("MaxDurationShouldAcceptAttestedReport (%v) must be less than or equal to %v", cfg.MaxDurationShouldAcceptAttestedReport, maxMaxDurationPluginCall) + } + if !(minMaxDurationPluginCall <= cfg.MaxDurationShouldTransmitAcceptedReport) { + return fmt.Errorf("MaxDurationShouldTransmitAcceptedReport (%v) must be greater than or equal to %v", cfg.MaxDurationShouldTransmitAcceptedReport, minMaxDurationPluginCall) + } + if !(cfg.MaxDurationShouldTransmitAcceptedReport <= maxMaxDurationPluginCall) { + return fmt.Errorf("MaxDurationShouldTransmitAcceptedReport (%v) must be less than or equal to %v", cfg.MaxDurationShouldTransmitAcceptedReport, maxMaxDurationPluginCall) + } + + // We don't check DeltaGrace, DeltaStage since none of them would exhaust + // the oracle's resources even if they are all set to 0. + return nil +} diff --git a/offchainreporting2plus/internal/config/ocr3_1config/serialize.go b/offchainreporting2plus/internal/config/ocr3_1config/serialize.go new file mode 100644 index 00000000..382517b7 --- /dev/null +++ b/offchainreporting2plus/internal/config/ocr3_1config/serialize.go @@ -0,0 +1,297 @@ +package ocr3_1config + +import ( + "fmt" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/smartcontractkit/libocr/internal/util" + "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config" + "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "golang.org/x/crypto/curve25519" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/runtime/protoimpl" +) + +// Serialized configs must be no larger than this (arbitrary bound, to prevent +// resource exhaustion attacks) +var maxSerializedOffchainConfigSize = 2_000_000 + +// offchainConfig contains the contents of the oracle Config objects +// which need to be serialized +type offchainConfig struct { + DeltaProgress time.Duration + DeltaResend *time.Duration + DeltaInitial *time.Duration + DeltaRound time.Duration + DeltaGrace time.Duration + DeltaReportsPlusPrecursorRequest *time.Duration + DeltaStage time.Duration + + // state sync + DeltaStateSyncSummaryInterval *time.Duration + + // block sync + DeltaBlockSyncMinRequestToSameOracleInterval *time.Duration + DeltaBlockSyncResponseTimeout *time.Duration + MaxBlocksPerBlockSyncResponse *int + MaxParallelRequestedBlocks *uint64 + + // tree sync + DeltaTreeSyncMinRequestToSameOracleInterval *time.Duration + DeltaTreeSyncResponseTimeout *time.Duration + MaxTreeSyncChunkKeys *int + MaxTreeSyncChunkKeysPlusValuesBytes *int + MaxParallelTreeSyncChunkFetches *int + + // snapshotting + SnapshotInterval *uint64 + MaxHistoricalSnapshotsRetained *uint64 + + // blobs + DeltaBlobOfferMinRequestToSameOracleInterval *time.Duration + DeltaBlobOfferResponseTimeout *time.Duration + DeltaBlobBroadcastGrace *time.Duration + DeltaBlobChunkMinRequestToSameOracleInterval *time.Duration + DeltaBlobChunkResponseTimeout *time.Duration + BlobChunkBytes *int + + RMax uint64 + S []int + OffchainPublicKeys []types.OffchainPublicKey + PeerIDs []string + ReportingPluginConfig []byte + MaxDurationInitialization time.Duration + WarnDurationQuery time.Duration + WarnDurationObservation time.Duration + WarnDurationValidateObservation time.Duration + WarnDurationObservationQuorum time.Duration + WarnDurationStateTransition time.Duration + WarnDurationCommitted time.Duration + MaxDurationShouldAcceptAttestedReport time.Duration + MaxDurationShouldTransmitAcceptedReport time.Duration + SharedSecretEncryptions config.SharedSecretEncryptions +} + +func checkSize(serializedOffchainConfig []byte) error { + if len(serializedOffchainConfig) <= maxSerializedOffchainConfigSize { + return nil + } else { + return fmt.Errorf("OffchainConfig length is %d bytes which is greater than the max %d", + len(serializedOffchainConfig), + maxSerializedOffchainConfigSize, + ) + } +} + +// serialize returns a binary serialization of o +func (o offchainConfig) serialize() []byte { + offchainConfigProto := enprotoOffchainConfig(o) + rv, err := proto.Marshal(&offchainConfigProto) + if err != nil { + panic(err) + } + if err := checkSize(rv); err != nil { + panic(err.Error()) + } + return rv +} + +func deserializeOffchainConfig( + b []byte, +) (offchainConfig, error) { + if err := checkSize(b); err != nil { + return offchainConfig{}, err + } + + offchainConfigPB := OffchainConfigProto{} + if err := proto.Unmarshal(b, &offchainConfigPB); err != nil { + return offchainConfig{}, fmt.Errorf("could not unmarshal ContractConfig.OffchainConfig protobuf: %w", err) + } + + return deprotoOffchainConfig(&offchainConfigPB) +} + +func deprotoOffchainConfig( + offchainConfigProto *OffchainConfigProto, +) (offchainConfig, error) { + S := make([]int, 0, len(offchainConfigProto.GetS())) + for _, elem := range offchainConfigProto.GetS() { + S = append(S, int(elem)) + } + + offchainPublicKeys := make([]types.OffchainPublicKey, 0, len(offchainConfigProto.GetOffchainPublicKeys())) + for _, ocpkRaw := range offchainConfigProto.GetOffchainPublicKeys() { + var ocpk types.OffchainPublicKey + if len(ocpkRaw) != len(ocpk) { + return offchainConfig{}, fmt.Errorf("invalid offchain public key: %x", ocpkRaw) + } + copy(ocpk[:], ocpkRaw) + offchainPublicKeys = append(offchainPublicKeys, ocpk) + } + + sharedSecretEncryptions, err := deprotoSharedSecretEncryptions(offchainConfigProto.GetSharedSecretEncryptions()) + if err != nil { + return offchainConfig{}, fmt.Errorf("could not unmarshal shared protobuf: %w", err) + } + + return offchainConfig{ + time.Duration(offchainConfigProto.GetDeltaProgressNanoseconds()), + util.PointerIntegerCast[time.Duration](offchainConfigProto.DeltaResendNanoseconds), + util.PointerIntegerCast[time.Duration](offchainConfigProto.DeltaInitialNanoseconds), + time.Duration(offchainConfigProto.GetDeltaRoundNanoseconds()), + time.Duration(offchainConfigProto.GetDeltaGraceNanoseconds()), + util.PointerIntegerCast[time.Duration](offchainConfigProto.DeltaReportsPlusPrecursorRequestNanoseconds), + time.Duration(offchainConfigProto.GetDeltaStageNanoseconds()), + + // state sync + util.PointerIntegerCast[time.Duration](offchainConfigProto.DeltaStateSyncSummaryIntervalNanoseconds), + + // block sync + util.PointerIntegerCast[time.Duration](offchainConfigProto.DeltaBlockSyncMinRequestToSameOracleIntervalNanoseconds), + util.PointerIntegerCast[time.Duration](offchainConfigProto.DeltaBlockSyncResponseTimeoutNanoseconds), + util.PointerIntegerCast[int](offchainConfigProto.MaxBlocksPerBlockSyncResponse), + offchainConfigProto.MaxParallelRequestedBlocks, + + // tree sync + util.PointerIntegerCast[time.Duration](offchainConfigProto.DeltaTreeSyncMinRequestToSameOracleIntervalNanoseconds), + util.PointerIntegerCast[time.Duration](offchainConfigProto.DeltaTreeSyncResponseTimeoutNanoseconds), + util.PointerIntegerCast[int](offchainConfigProto.MaxTreeSyncChunkKeys), + util.PointerIntegerCast[int](offchainConfigProto.MaxTreeSyncChunkKeysPlusValuesBytes), + util.PointerIntegerCast[int](offchainConfigProto.MaxParallelTreeSyncChunkFetches), + + // snapshotting + offchainConfigProto.SnapshotInterval, + offchainConfigProto.MaxHistoricalSnapshotsRetained, + + // blobs + util.PointerIntegerCast[time.Duration](offchainConfigProto.DeltaBlobOfferMinRequestToSameOracleIntervalNanoseconds), + util.PointerIntegerCast[time.Duration](offchainConfigProto.DeltaBlobOfferResponseTimeoutNanoseconds), + util.PointerIntegerCast[time.Duration](offchainConfigProto.DeltaBlobBroadcastGraceNanoseconds), + util.PointerIntegerCast[time.Duration](offchainConfigProto.DeltaBlobChunkMinRequestToSameOracleIntervalNanoseconds), + util.PointerIntegerCast[time.Duration](offchainConfigProto.DeltaBlobChunkResponseTimeoutNanoseconds), + util.PointerIntegerCast[int](offchainConfigProto.BlobChunkBytes), + + offchainConfigProto.GetRMax(), + S, + offchainPublicKeys, + offchainConfigProto.GetPeerIds(), + offchainConfigProto.GetReportingPluginConfig(), + time.Duration(offchainConfigProto.GetMaxDurationInitializationNanoseconds()), + time.Duration(offchainConfigProto.GetWarnDurationQueryNanoseconds()), + time.Duration(offchainConfigProto.GetWarnDurationObservationNanoseconds()), + time.Duration(offchainConfigProto.GetWarnDurationValidateObservationNanoseconds()), + time.Duration(offchainConfigProto.GetWarnDurationObservationQuorumNanoseconds()), + time.Duration(offchainConfigProto.GetWarnDurationStateTransitionNanoseconds()), + time.Duration(offchainConfigProto.GetWarnDurationCommittedNanoseconds()), + time.Duration(offchainConfigProto.GetMaxDurationShouldAcceptAttestedReportNanoseconds()), + time.Duration(offchainConfigProto.GetMaxDurationShouldTransmitAcceptedReportNanoseconds()), + sharedSecretEncryptions, + }, nil +} + +func deprotoSharedSecretEncryptions(sharedSecretEncryptionsProto *SharedSecretEncryptionsProto) (config.SharedSecretEncryptions, error) { + var diffieHellmanPoint [curve25519.PointSize]byte + if len(diffieHellmanPoint) != len(sharedSecretEncryptionsProto.GetDiffieHellmanPoint()) { + return config.SharedSecretEncryptions{}, fmt.Errorf("DiffieHellmanPoint has wrong length. Expected %v bytes, got %v bytes", len(diffieHellmanPoint), len(sharedSecretEncryptionsProto.GetDiffieHellmanPoint())) + } + copy(diffieHellmanPoint[:], sharedSecretEncryptionsProto.GetDiffieHellmanPoint()) + + var sharedSecretHash common.Hash + if len(sharedSecretHash) != len(sharedSecretEncryptionsProto.GetSharedSecretHash()) { + return config.SharedSecretEncryptions{}, fmt.Errorf("sharedSecretHash has wrong length. Expected %v bytes, got %v bytes", len(sharedSecretHash), len(sharedSecretEncryptionsProto.GetSharedSecretHash())) + } + copy(sharedSecretHash[:], sharedSecretEncryptionsProto.GetSharedSecretHash()) + + encryptions := make([]config.EncryptedSharedSecret, 0, len(sharedSecretEncryptionsProto.GetEncryptions())) + for i, encryptionRaw := range sharedSecretEncryptionsProto.GetEncryptions() { + var encryption config.EncryptedSharedSecret + if len(encryption) != len(encryptionRaw) { + return config.SharedSecretEncryptions{}, fmt.Errorf("Encryptions[%v] has wrong length. Expected %v bytes, got %v bytes", i, len(encryption), len(encryptionRaw)) + } + copy(encryption[:], encryptionRaw) + encryptions = append(encryptions, encryption) + } + + return config.SharedSecretEncryptions{ + diffieHellmanPoint, + sharedSecretHash, + encryptions, + }, nil +} + +func enprotoOffchainConfig(o offchainConfig) OffchainConfigProto { + s := make([]uint32, len(o.S)) + for i, d := range o.S { + s[i] = uint32(d) + } + offchainPublicKeys := make([][]byte, 0, len(o.OffchainPublicKeys)) + for _, k := range o.OffchainPublicKeys { + offchainPublicKeys = append(offchainPublicKeys, k[:]) + } + sharedSecretEncryptions := enprotoSharedSecretEncryptions(o.SharedSecretEncryptions) + return OffchainConfigProto{ + // zero-initialize protobuf built-ins + protoimpl.MessageState{}, + 0, + nil, + // fields + uint64(o.DeltaProgress), + util.PointerIntegerCast[uint64](o.DeltaResend), + util.PointerIntegerCast[uint64](o.DeltaInitial), + uint64(o.DeltaRound), + uint64(o.DeltaGrace), + util.PointerIntegerCast[uint64](o.DeltaReportsPlusPrecursorRequest), + uint64(o.DeltaStage), + util.PointerIntegerCast[uint64](o.DeltaStateSyncSummaryInterval), + util.PointerIntegerCast[uint64](o.DeltaBlockSyncMinRequestToSameOracleInterval), + util.PointerIntegerCast[uint64](o.DeltaBlockSyncResponseTimeout), + util.PointerIntegerCast[uint32](o.MaxBlocksPerBlockSyncResponse), + util.PointerIntegerCast[uint64](o.MaxParallelRequestedBlocks), + util.PointerIntegerCast[uint64](o.DeltaTreeSyncMinRequestToSameOracleInterval), + util.PointerIntegerCast[uint64](o.DeltaTreeSyncResponseTimeout), + util.PointerIntegerCast[uint32](o.MaxTreeSyncChunkKeys), + util.PointerIntegerCast[uint32](o.MaxTreeSyncChunkKeysPlusValuesBytes), + util.PointerIntegerCast[uint32](o.MaxParallelTreeSyncChunkFetches), + util.PointerIntegerCast[uint64](o.SnapshotInterval), + util.PointerIntegerCast[uint64](o.MaxHistoricalSnapshotsRetained), + util.PointerIntegerCast[uint64](o.DeltaBlobOfferMinRequestToSameOracleInterval), + util.PointerIntegerCast[uint64](o.DeltaBlobOfferResponseTimeout), + util.PointerIntegerCast[uint64](o.DeltaBlobBroadcastGrace), + util.PointerIntegerCast[uint64](o.DeltaBlobChunkMinRequestToSameOracleInterval), + util.PointerIntegerCast[uint64](o.DeltaBlobChunkResponseTimeout), + util.PointerIntegerCast[uint32](o.BlobChunkBytes), + o.RMax, + s, + offchainPublicKeys, + o.PeerIDs, + o.ReportingPluginConfig, + uint64(o.MaxDurationInitialization), + uint64(o.WarnDurationQuery), + uint64(o.WarnDurationObservation), + uint64(o.WarnDurationValidateObservation), + uint64(o.WarnDurationObservationQuorum), + uint64(o.WarnDurationStateTransition), + uint64(o.WarnDurationCommitted), + uint64(o.MaxDurationShouldAcceptAttestedReport), + uint64(o.MaxDurationShouldTransmitAcceptedReport), + &sharedSecretEncryptions, + } +} + +func enprotoSharedSecretEncryptions(e config.SharedSecretEncryptions) SharedSecretEncryptionsProto { + encs := make([][]byte, 0, len(e.Encryptions)) + for _, enc := range e.Encryptions { + encs = append(encs, enc[:]) + } + return SharedSecretEncryptionsProto{ + // zero-initialize protobuf built-ins + protoimpl.MessageState{}, + 0, + nil, + // fields + e.DiffieHellmanPoint[:], + e.SharedSecretHash[:], + encs, + } +} diff --git a/offchainreporting2plus/internal/config/ocr3_1config/shared_config.go b/offchainreporting2plus/internal/config/ocr3_1config/shared_config.go new file mode 100644 index 00000000..8fbe6285 --- /dev/null +++ b/offchainreporting2plus/internal/config/ocr3_1config/shared_config.go @@ -0,0 +1,236 @@ +package ocr3_1config + +import ( + "bytes" + "crypto/hmac" + "crypto/rand" + "crypto/sha256" + "fmt" + "math" + + "github.com/ethereum/go-ethereum/common" + "github.com/pkg/errors" + "github.com/smartcontractkit/libocr/commontypes" + "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config" + "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ethcontractconfig" + "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3types" + "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "golang.org/x/crypto/curve25519" +) + +// SharedConfig is the configuration shared by all oracles running an instance +// of the protocol. It's disseminated through the smart contract, +// but parts of it are encrypted so that only oracles can access them. +type SharedConfig struct { + PublicConfig + SharedSecret *[config.SharedSecretSize]byte +} + +func (c *SharedConfig) LeaderSelectionKey() [16]byte { + var result [16]byte + mac := hmac.New(sha256.New, c.SharedSecret[:]) + _, _ = mac.Write([]byte("chainlink offchain reporting v3 leader selection key")) + _, _ = mac.Write(c.ConfigDigest[:]) + _ = copy(result[:], mac.Sum(nil)) + return result +} + +func (c *SharedConfig) TransmissionOrderKey() [16]byte { + var result [16]byte + mac := hmac.New(sha256.New, c.SharedSecret[:]) + _, _ = mac.Write([]byte("chainlink offchain reporting v3 transmission order key")) + _, _ = mac.Write(c.ConfigDigest[:]) + _ = copy(result[:], mac.Sum(nil)) + return result +} + +func SharedConfigFromContractConfig[RI any]( + skipInsaneForProductionChecks bool, + change types.ContractConfig, + offchainKeyring types.OffchainKeyring, + onchainKeyring ocr3types.OnchainKeyring[RI], + peerID string, + transmitAccount types.Account, +) (SharedConfig, commontypes.OracleID, error) { + publicConfig, encSharedSecret, err := publicConfigFromContractConfig(skipInsaneForProductionChecks, change) + if err != nil { + return SharedConfig{}, 0, err + } + + oracleID := commontypes.OracleID(math.MaxUint8) + { + onchainPublicKey := onchainKeyring.PublicKey() + offchainPublicKey := offchainKeyring.OffchainPublicKey() + var found bool + for i, identity := range publicConfig.OracleIdentities { + if bytes.Equal(identity.OnchainPublicKey, onchainPublicKey) { + if identity.OffchainPublicKey != offchainPublicKey { + return SharedConfig{}, 0, errors.Errorf( + "OnchainPublicKey %x in publicConfig matches "+ + "mine, but OffchainPublicKey does not: %v (config) vs %v (mine)", + onchainPublicKey, identity.OffchainPublicKey, offchainPublicKey) + } + if identity.PeerID != peerID { + return SharedConfig{}, 0, errors.Errorf( + "OnchainPublicKey %x in publicConfig matches "+ + "mine, but PeerID does not: %v (config) vs %v (mine)", + onchainPublicKey, identity.PeerID, peerID) + } + if identity.TransmitAccount != transmitAccount { + return SharedConfig{}, 0, errors.Errorf( + "OnchainPublicKey %x in publicConfig matches "+ + "mine, but TransmitAccount does not: %v (config) vs %v (mine)", + onchainPublicKey, identity.TransmitAccount, transmitAccount) + } + oracleID = commontypes.OracleID(i) + found = true + } + } + + if !found { + return SharedConfig{}, + 0, + fmt.Errorf("could not find my OnchainPublicKey %x in publicConfig", onchainPublicKey) + } + } + + x, err := encSharedSecret.Decrypt(oracleID, offchainKeyring) + if err != nil { + return SharedConfig{}, 0, fmt.Errorf("could not decrypt shared secret: %w", err) + } + + return SharedConfig{ + publicConfig, + x, + }, oracleID, nil + +} + +func ContractSetConfigArgsFromSharedConfigDeterministic( + c SharedConfig, + sharedSecretEncryptionPublicKeys []types.ConfigEncryptionPublicKey, + ephemeralSk *[curve25519.ScalarSize]byte, +) ( + signers []types.OnchainPublicKey, + transmitters []types.Account, + f uint8, + onchainConfig []byte, + offchainConfigVersion uint64, + offchainConfig_ []byte, + err error, +) { + offChainPublicKeys := []types.OffchainPublicKey{} + peerIDs := []string{} + for _, identity := range c.OracleIdentities { + signers = append(signers, identity.OnchainPublicKey) + transmitters = append(transmitters, identity.TransmitAccount) + offChainPublicKeys = append(offChainPublicKeys, identity.OffchainPublicKey) + peerIDs = append(peerIDs, identity.PeerID) + } + sharedSecretEncryptions, err := config.EncryptSharedSecretDeterministic( + sharedSecretEncryptionPublicKeys, + c.SharedSecret, + ephemeralSk, + ) + if err != nil { + return nil, nil, 0, nil, 0, nil, err + } + offchainConfig_ = (offchainConfig{ + c.DeltaProgress, + c.DeltaResend, + c.DeltaInitial, + c.DeltaRound, + c.DeltaGrace, + c.DeltaReportsPlusPrecursorRequest, + c.DeltaStage, + + // state sync + c.DeltaStateSyncSummaryInterval, + + // block sync + c.DeltaBlockSyncMinRequestToSameOracleInterval, + c.DeltaBlockSyncResponseTimeout, + c.MaxBlocksPerBlockSyncResponse, + c.MaxParallelRequestedBlocks, + + // tree sync + c.DeltaTreeSyncMinRequestToSameOracleInterval, + c.DeltaTreeSyncResponseTimeout, + c.MaxTreeSyncChunkKeys, + c.MaxTreeSyncChunkKeysPlusValuesBytes, + c.MaxParallelTreeSyncChunkFetches, + + // snapshotting + c.SnapshotInterval, + c.MaxHistoricalSnapshotsRetained, + + // blobs + c.DeltaBlobOfferMinRequestToSameOracleInterval, + c.DeltaBlobOfferResponseTimeout, + c.DeltaBlobBroadcastGrace, + c.DeltaBlobChunkMinRequestToSameOracleInterval, + c.DeltaBlobChunkResponseTimeout, + c.BlobChunkBytes, + + c.RMax, + c.S, + offChainPublicKeys, + peerIDs, + c.ReportingPluginConfig, + c.MaxDurationInitialization, + c.WarnDurationQuery, + c.WarnDurationObservation, + c.WarnDurationValidateObservation, + c.WarnDurationObservationQuorum, + c.WarnDurationStateTransition, + c.WarnDurationCommitted, + c.MaxDurationShouldAcceptAttestedReport, + c.MaxDurationShouldTransmitAcceptedReport, + sharedSecretEncryptions, + }).serialize() + return signers, transmitters, uint8(c.F), c.OnchainConfig, config.OCR3_1OffchainConfigVersion, offchainConfig_, nil +} + +func XXXContractSetConfigArgsFromSharedConfigEthereum( + c SharedConfig, + sharedSecretEncryptionPublicKeys []types.ConfigEncryptionPublicKey, +) ( + setConfigArgs ethcontractconfig.SetConfigArgs, + err error, +) { + ephemeralSk := [curve25519.ScalarSize]byte{} + if _, err := rand.Read(ephemeralSk[:]); err != nil { + return ethcontractconfig.SetConfigArgs{}, err + } + + signerOnchainPublicKeys, transmitterAccounts, f, onchainConfig, offchainConfigVersion, offchainConfig, err := + ContractSetConfigArgsFromSharedConfigDeterministic(c, sharedSecretEncryptionPublicKeys, &ephemeralSk) + if err != nil { + return ethcontractconfig.SetConfigArgs{}, err + } + + var signers []common.Address + for _, signer := range signerOnchainPublicKeys { + if len(signer) != 20 { + return ethcontractconfig.SetConfigArgs{}, fmt.Errorf("OnChainPublicKey has wrong length for address") + } + signers = append(signers, common.BytesToAddress(signer)) + } + + var transmitters []common.Address + for _, transmitter := range transmitterAccounts { + if !common.IsHexAddress(string(transmitter)) { + return ethcontractconfig.SetConfigArgs{}, fmt.Errorf("TransmitAccount is not a valid Ethereum address") + } + transmitters = append(transmitters, common.HexToAddress(string(transmitter))) + } + + return ethcontractconfig.SetConfigArgs{ + signers, + transmitters, + f, + onchainConfig, + offchainConfigVersion, + offchainConfig, + }, nil +} diff --git a/offchainreporting2plus/internal/config/offchain_config_versions.go b/offchainreporting2plus/internal/config/offchain_config_versions.go index 845762fa..164ca4e4 100644 --- a/offchainreporting2plus/internal/config/offchain_config_versions.go +++ b/offchainreporting2plus/internal/config/offchain_config_versions.go @@ -1,6 +1,7 @@ package config const ( - OCR2OffchainConfigVersion = 2 - OCR3OffchainConfigVersion = 30 + OCR2OffchainConfigVersion = 2 + OCR3OffchainConfigVersion = 30 + OCR3_1OffchainConfigVersion = 310 ) diff --git a/offchainreporting2plus/internal/managed/limits/ocr3_1_limits.go b/offchainreporting2plus/internal/managed/limits/ocr3_1_limits.go index aefc3194..28cddbe7 100644 --- a/offchainreporting2plus/internal/managed/limits/ocr3_1_limits.go +++ b/offchainreporting2plus/internal/managed/limits/ocr3_1_limits.go @@ -2,42 +2,45 @@ package limits import ( "crypto/ed25519" + "crypto/sha256" "fmt" "math" "math/big" + "math/bits" "time" "github.com/smartcontractkit/libocr/internal/jmt" - "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3config" + "github.com/smartcontractkit/libocr/internal/mt" + "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config" "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/ocr3_1/protocol" "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3_1types" "github.com/smartcontractkit/libocr/offchainreporting2plus/types" ) type OCR3_1SerializedLengthLimits struct { - MaxLenMsgNewEpoch int - MaxLenMsgEpochStartRequest int - MaxLenMsgEpochStart int - MaxLenMsgRoundStart int - MaxLenMsgObservation int - MaxLenMsgProposal int - MaxLenMsgPrepare int - MaxLenMsgCommit int - MaxLenMsgReportSignatures int - MaxLenMsgCertifiedCommitRequest int - MaxLenMsgCertifiedCommit int - MaxLenMsgStateSyncSummary int - MaxLenMsgBlockSyncRequest int - MaxLenMsgBlockSyncResponse int - MaxLenMsgTreeSyncChunkRequest int - MaxLenMsgTreeSyncChunkResponse int - MaxLenMsgBlobOffer int - MaxLenMsgBlobOfferResponse int - MaxLenMsgBlobChunkRequest int - MaxLenMsgBlobChunkResponse int + MaxLenMsgNewEpoch int + MaxLenMsgEpochStartRequest int + MaxLenMsgEpochStart int + MaxLenMsgRoundStart int + MaxLenMsgObservation int + MaxLenMsgProposal int + MaxLenMsgPrepare int + MaxLenMsgCommit int + MaxLenMsgReportSignatures int + MaxLenMsgReportsPlusPrecursorRequest int + MaxLenMsgReportsPlusPrecursor int + MaxLenMsgStateSyncSummary int + MaxLenMsgBlockSyncRequest int + MaxLenMsgBlockSyncResponse int + MaxLenMsgTreeSyncChunkRequest int + MaxLenMsgTreeSyncChunkResponse int + MaxLenMsgBlobOffer int + MaxLenMsgBlobOfferResponse int + MaxLenMsgBlobChunkRequest int + MaxLenMsgBlobChunkResponse int } -func OCR3_1Limits(cfg ocr3config.PublicConfig, pluginLimits ocr3_1types.ReportingPluginLimits, maxSigLen int) (types.BinaryNetworkEndpointLimits, types.BinaryNetworkEndpointLimits, OCR3_1SerializedLengthLimits, error) { +func OCR3_1Limits(cfg ocr3_1config.PublicConfig, pluginLimits ocr3_1types.ReportingPluginLimits, maxSigLen int) (types.BinaryNetworkEndpointLimits, types.BinaryNetworkEndpointLimits, OCR3_1SerializedLengthLimits, error) { overflow := false // These two helper functions add/multiply together a bunch of numbers and set overflow to true if the result @@ -68,30 +71,27 @@ func OCR3_1Limits(cfg ocr3config.PublicConfig, pluginLimits ocr3_1types.Reportin const sigOverhead = 10 const overhead = 256 - maxLenStateTransitionOutputs := add(mul(2, pluginLimits.MaxKeyValueModifiedKeysPlusValuesLength), overhead) + maxLenStateTransitionOutputs := add( + pluginLimits.MaxKeyValueModifiedKeysPlusValuesBytes, + mul( + pluginLimits.MaxKeyValueModifiedKeys, + repeatedOverhead, + ), + ) maxLenCertifiedPrepareOrCommit := add(mul(ed25519.SignatureSize+sigOverhead, cfg.ByzQuorumSize()), - len(protocol.StateTransitionInputsDigest{}), - maxLenStateTransitionOutputs, - len(protocol.StateRootDigest{}), - pluginLimits.MaxReportsPlusPrecursorLength, - overhead) - maxLenCertifiedCommittedReports := add(mul(ed25519.SignatureSize+sigOverhead, cfg.ByzQuorumSize()), - len(protocol.StateTransitionInputsDigest{}), - len(protocol.StateTransitionOutputDigest{}), - len(protocol.StateRootDigest{}), - pluginLimits.MaxReportsPlusPrecursorLength, + sha256.Size*3, overhead) maxLenMsgNewEpoch := overhead maxLenMsgEpochStartRequest := add(maxLenCertifiedPrepareOrCommit, overhead) maxLenMsgEpochStart := add(maxLenCertifiedPrepareOrCommit, mul(ed25519.SignatureSize+sigOverhead, cfg.ByzQuorumSize()), overhead) - maxLenMsgRoundStart := add(pluginLimits.MaxQueryLength, overhead) - maxLenMsgObservation := add(pluginLimits.MaxObservationLength, overhead) - maxLenMsgProposal := add(mul(add(pluginLimits.MaxObservationLength, ed25519.SignatureSize+sigOverhead), cfg.N()), overhead) + maxLenMsgRoundStart := add(pluginLimits.MaxQueryBytes, overhead) + maxLenMsgObservation := add(pluginLimits.MaxObservationBytes, overhead) + maxLenMsgProposal := add(mul(add(pluginLimits.MaxObservationBytes, ed25519.SignatureSize+sigOverhead), cfg.N()), overhead) maxLenMsgPrepare := overhead maxLenMsgCommit := overhead maxLenMsgReportSignatures := add(mul(add(maxSigLen, sigOverhead), pluginLimits.MaxReportCount), overhead) - maxLenMsgCertifiedCommitRequest := overhead - maxLenMsgCertifiedCommit := add(maxLenCertifiedCommittedReports, overhead) + maxLenMsgReportsPlusPrecursorRequest := overhead + maxLenMsgReportsPlusPrecursor := add(pluginLimits.MaxReportsPlusPrecursorBytes, overhead) maxLenMsgStateSyncSummary := overhead // tree sync messages @@ -108,9 +108,9 @@ func OCR3_1Limits(cfg ocr3config.PublicConfig, pluginLimits ocr3_1types.Reportin ), ) maxLenMsgTreeSyncChunkResponseKeyValues := add( - protocol.MaxTreeSyncChunkKeysPlusValuesLength, + cfg.GetMaxTreeSyncChunkKeysPlusValuesBytes(), mul( // repeated overheads - protocol.MaxTreeSyncChunkKeys, + cfg.GetMaxTreeSyncChunkKeys(), repeatedOverhead, // key-value add( repeatedOverhead, // key @@ -132,16 +132,19 @@ func OCR3_1Limits(cfg ocr3config.PublicConfig, pluginLimits ocr3_1types.Reportin // block sync messages maxLenMsgBlockSyncRequest := overhead - maxLenAttestedStateTransitionBlock := maxLenCertifiedPrepareOrCommit - maxLenMsgBlockSyncResponse := add(mul(protocol.MaxBlocksPerBlockSyncResponse, maxLenAttestedStateTransitionBlock), overhead) + maxLenAttestedStateTransitionBlock := add(maxLenCertifiedPrepareOrCommit, maxLenStateTransitionOutputs) + maxLenMsgBlockSyncResponse := add(mul(cfg.GetMaxBlocksPerBlockSyncResponse(), maxLenAttestedStateTransitionBlock), overhead) // blob exchange messages - const blobChunkDigestSize = len(protocol.BlobChunkDigest{}) - maxNumBlobChunks := (pluginLimits.MaxBlobPayloadLength + protocol.BlobChunkSize - 1) / protocol.BlobChunkSize - maxLenMsgBlobOffer := add(mul(blobChunkDigestSize, maxNumBlobChunks), overhead) - maxLenMsgBlobChunkRequest := add(blobChunkDigestSize, overhead) - maxLenMsgBlobChunkResponse := add(blobChunkDigestSize, protocol.BlobChunkSize, overhead) - maxLenMsgBlobOfferResponse := add(blobChunkDigestSize, ed25519.SignatureSize+sigOverhead, overhead) + const blobDigestSize = len(protocol.BlobDigest{}) + cfgBlobChunkSize := cfg.GetBlobChunkBytes() + maxNumBlobChunks := (pluginLimits.MaxBlobPayloadBytes + cfgBlobChunkSize - 1) / cfgBlobChunkSize + maxBlobChunksDigestProofElements := bits.Len(uint(maxNumBlobChunks)) + 1 + maxLenMsgBlobOffer := add(blobDigestSize, overhead) + maxLenMsgBlobChunkRequest := add(blobDigestSize, overhead) + maxLenMsgBlobChunkResponse := add(blobDigestSize, cfgBlobChunkSize, + mul(maxBlobChunksDigestProofElements, add(repeatedOverhead, len(mt.Digest{}))), overhead) + maxLenMsgBlobOfferResponse := add(blobDigestSize, ed25519.SignatureSize+sigOverhead, overhead) maxDefaultPriorityMessageSize := max( maxLenMsgNewEpoch, @@ -153,8 +156,8 @@ func OCR3_1Limits(cfg ocr3config.PublicConfig, pluginLimits ocr3_1types.Reportin maxLenMsgPrepare, maxLenMsgCommit, maxLenMsgReportSignatures, - maxLenMsgCertifiedCommitRequest, - maxLenMsgCertifiedCommit, + maxLenMsgReportsPlusPrecursorRequest, + maxLenMsgReportsPlusPrecursor, maxLenMsgBlobOffer, maxLenMsgBlobChunkRequest, ) @@ -167,24 +170,24 @@ func OCR3_1Limits(cfg ocr3config.PublicConfig, pluginLimits ocr3_1types.Reportin minRoundInterval := math.Max(float64(cfg.DeltaRound), float64(cfg.DeltaGrace)) - minEpochInterval := math.Min(float64(cfg.DeltaProgress), math.Min(float64(cfg.DeltaInitial), float64(cfg.RMax)*float64(minRoundInterval))) + minEpochInterval := math.Min(float64(cfg.DeltaProgress), math.Min(float64(cfg.GetDeltaInitial()), float64(cfg.RMax)*float64(minRoundInterval))) - defaultPriorityMessagesRate := (1.0*float64(time.Second)/float64(cfg.DeltaResend) + + defaultPriorityMessagesRate := (1.0*float64(time.Second)/float64(cfg.GetDeltaResend()) + 3.0*float64(time.Second)/minEpochInterval + 8.0*float64(time.Second)/float64(minRoundInterval) + - 2.0*float64(time.Second)/float64(protocol.DeltaBlobOfferBroadcast) + - 1.0*float64(time.Second)/float64(protocol.DeltaBlobChunkRequest)) * 1.2 + 2.0*float64(time.Second)/float64(cfg.GetDeltaBlobOfferMinRequestToSameOracleInterval()) + + 1.0*float64(time.Second)/float64(cfg.GetDeltaBlobChunkMinRequestToSameOracleInterval())) * 1.2 - lowPriorityMessagesRate := (1.0*float64(time.Second)/float64(protocol.DeltaMinBlockSyncRequest) + - 1.0*float64(time.Second)/float64(protocol.DeltaMinTreeSyncRequest) + - 1.0*float64(time.Second)/float64(protocol.DeltaStateSyncHeartbeat)) * 1.2 + lowPriorityMessagesRate := (1.0*float64(time.Second)/float64(cfg.GetDeltaBlockSyncMinRequestToSameOracleInterval()) + + 1.0*float64(time.Second)/float64(cfg.GetDeltaTreeSyncMinRequestToSameOracleInterval()) + + 1.0*float64(time.Second)/float64(cfg.GetDeltaStateSyncSummaryInterval())) * 1.2 defaultPriorityMessagesCapacity := mul(15, 3) lowPriorityMessagesCapacity := mul(3, 3) // we don't multiply bytesRate by a safetyMargin since we already have a generous overhead on each message - defaultPriorityBytesRate := float64(time.Second)/float64(cfg.DeltaResend)*float64(maxLenMsgNewEpoch) + + defaultPriorityBytesRate := float64(time.Second)/float64(cfg.GetDeltaResend())*float64(maxLenMsgNewEpoch) + float64(time.Second)/float64(minEpochInterval)*float64(maxLenMsgNewEpoch) + float64(time.Second)/float64(minRoundInterval)*float64(maxLenMsgPrepare) + float64(time.Second)/float64(minRoundInterval)*float64(maxLenMsgCommit) + @@ -194,14 +197,14 @@ func OCR3_1Limits(cfg ocr3config.PublicConfig, pluginLimits ocr3_1types.Reportin float64(time.Second)/float64(minRoundInterval)*float64(maxLenMsgProposal) + float64(time.Second)/float64(minEpochInterval)*float64(maxLenMsgEpochStartRequest) + float64(time.Second)/float64(minRoundInterval)*float64(maxLenMsgObservation) + - float64(time.Second)/float64(minRoundInterval)*float64(maxLenMsgCertifiedCommitRequest) + - float64(time.Second)/float64(minRoundInterval)*float64(maxLenMsgCertifiedCommit) + - float64(time.Second)/float64(protocol.DeltaBlobOfferBroadcast)*float64(maxLenMsgBlobOffer) + // blob-related messages - float64(time.Second)/float64(protocol.DeltaBlobChunkRequest)*float64(maxLenMsgBlobChunkRequest) + float64(time.Second)/float64(minRoundInterval)*float64(maxLenMsgReportsPlusPrecursorRequest) + + float64(time.Second)/float64(minRoundInterval)*float64(maxLenMsgReportsPlusPrecursor) + + float64(time.Second)/float64(cfg.GetDeltaBlobOfferMinRequestToSameOracleInterval())*float64(maxLenMsgBlobOffer) + // blob-related messages + float64(time.Second)/float64(cfg.GetDeltaBlobChunkMinRequestToSameOracleInterval())*float64(maxLenMsgBlobChunkRequest) - lowPriorityBytesRate := float64(time.Second)/float64(protocol.DeltaStateSyncHeartbeat)*float64(maxLenMsgStateSyncSummary) + - float64(time.Second)/float64(protocol.DeltaMinBlockSyncRequest)*float64(maxLenMsgBlockSyncRequest) + - float64(time.Second)/float64(protocol.DeltaMinTreeSyncRequest)*float64(maxLenMsgTreeSyncChunkRequest) + lowPriorityBytesRate := float64(time.Second)/float64(cfg.GetDeltaStateSyncSummaryInterval())*float64(maxLenMsgStateSyncSummary) + + float64(time.Second)/float64(cfg.GetDeltaBlockSyncMinRequestToSameOracleInterval())*float64(maxLenMsgBlockSyncRequest) + + float64(time.Second)/float64(cfg.GetDeltaTreeSyncMinRequestToSameOracleInterval())*float64(maxLenMsgTreeSyncChunkRequest) defaultPriorityBytesCapacity := mul(add( maxLenMsgNewEpoch, @@ -214,8 +217,8 @@ func OCR3_1Limits(cfg ocr3config.PublicConfig, pluginLimits ocr3_1types.Reportin maxLenMsgPrepare, maxLenMsgCommit, maxLenMsgReportSignatures, - maxLenMsgCertifiedCommitRequest, - maxLenMsgCertifiedCommit, + maxLenMsgReportsPlusPrecursorRequest, + maxLenMsgReportsPlusPrecursor, maxLenMsgBlobOffer, maxLenMsgBlobChunkRequest, maxLenMsgBlobOfferResponse, @@ -256,8 +259,8 @@ func OCR3_1Limits(cfg ocr3config.PublicConfig, pluginLimits ocr3_1types.Reportin maxLenMsgPrepare, maxLenMsgCommit, maxLenMsgReportSignatures, - maxLenMsgCertifiedCommitRequest, - maxLenMsgCertifiedCommit, + maxLenMsgReportsPlusPrecursorRequest, + maxLenMsgReportsPlusPrecursor, maxLenMsgStateSyncSummary, maxLenMsgBlockSyncRequest, maxLenMsgBlockSyncResponse, diff --git a/offchainreporting2plus/internal/managed/managed_ocr3_1_oracle.go b/offchainreporting2plus/internal/managed/managed_ocr3_1_oracle.go index 00bf9286..73e7ff7a 100644 --- a/offchainreporting2plus/internal/managed/managed_ocr3_1_oracle.go +++ b/offchainreporting2plus/internal/managed/managed_ocr3_1_oracle.go @@ -11,8 +11,7 @@ import ( "github.com/smartcontractkit/libocr/commontypes" "github.com/smartcontractkit/libocr/internal/loghelper" "github.com/smartcontractkit/libocr/internal/metricshelper" - "github.com/smartcontractkit/libocr/internal/util" - "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3config" + "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config" "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/managed/limits" "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/ocr3_1/protocol" "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/ocr3_1/serialization" @@ -72,15 +71,15 @@ func RunManagedOCR3_1Oracle[RI any]( configTracker, database, func(ctx context.Context, logger loghelper.LoggerWithContext, contractConfig types.ContractConfig) (err error, retry bool) { - skipResourceExhaustionChecks := localConfig.DevelopmentMode == types.EnableDangerousDevelopmentMode + skipInsaneForProductionChecks := localConfig.DevelopmentMode == types.EnableDangerousDevelopmentMode fromAccount, err := contractTransmitter.FromAccount(ctx) if err != nil { return fmt.Errorf("ManagedOCR3_1Oracle: error getting FromAccount: %w", err), true } - sharedConfig, oid, err := ocr3config.SharedConfigFromContractConfig( - skipResourceExhaustionChecks, + sharedConfig, oid, err := ocr3_1config.SharedConfigFromContractConfig( + skipInsaneForProductionChecks, contractConfig, offchainKeyring, onchainKeyring, @@ -113,7 +112,7 @@ func RunManagedOCR3_1Oracle[RI any]( blobEndpointWrapper := protocol.BlobEndpointWrapper{} - maxDurationInitialization := util.NilCoalesce(sharedConfig.MaxDurationInitialization, localConfig.DefaultMaxDurationInitialization) + maxDurationInitialization := sharedConfig.MaxDurationInitialization initCtx, initCancel := context.WithTimeout(ctx, maxDurationInitialization) defer initCancel() @@ -126,7 +125,7 @@ func RunManagedOCR3_1Oracle[RI any]( }, ) - reportingPlugin, reportingPluginInfo, err := reportingPluginFactory.NewReportingPlugin(initCtx, ocr3types.ReportingPluginConfig{ + reportingPlugin, reportingPluginInfo_, err := reportingPluginFactory.NewReportingPlugin(initCtx, ocr3types.ReportingPluginConfig{ sharedConfig.ConfigDigest, oid, sharedConfig.N(), @@ -134,8 +133,8 @@ func RunManagedOCR3_1Oracle[RI any]( sharedConfig.OnchainConfig, sharedConfig.ReportingPluginConfig, sharedConfig.DeltaRound, - sharedConfig.MaxDurationQuery, - sharedConfig.MaxDurationObservation, + sharedConfig.WarnDurationQuery, + sharedConfig.WarnDurationObservation, sharedConfig.MaxDurationShouldAcceptAttestedReport, sharedConfig.MaxDurationShouldTransmitAcceptedReport, }, &blobEndpointWrapper) @@ -151,6 +150,12 @@ func RunManagedOCR3_1Oracle[RI any]( "ManagedOCR3_1Oracle: error during reportingPlugin.Close()", ) + var reportingPluginInfo ocr3_1types.ReportingPluginInfo1 + switch rpi := reportingPluginInfo_.(type) { + case ocr3_1types.ReportingPluginInfo1: + reportingPluginInfo = rpi + } + if err := validateOCR3_1ReportingPluginLimits(reportingPluginInfo.Limits); err != nil { logger.Error("ManagedOCR3_1Oracle: invalid ReportingPluginInfo", commontypes.LogFields{ "error": err, @@ -232,7 +237,7 @@ func RunManagedOCR3_1Oracle[RI any]( logger, "ManagedOCR3_1Oracle: error during keyValueDatabase.Close()", ) - semanticOCR3_1KeyValueDatabase := shim.NewSemanticOCR3_1KeyValueDatabase(keyValueDatabase, reportingPluginInfo.Limits, logger, metricsRegisterer) + semanticOCR3_1KeyValueDatabase := shim.NewSemanticOCR3_1KeyValueDatabase(keyValueDatabase, reportingPluginInfo.Limits, sharedConfig.PublicConfig, logger, metricsRegisterer) protocol.RunOracle[RI]( ctx, @@ -264,27 +269,30 @@ func RunManagedOCR3_1Oracle[RI any]( func validateOCR3_1ReportingPluginLimits(limits ocr3_1types.ReportingPluginLimits) error { var err error - if !(0 <= limits.MaxQueryLength && limits.MaxQueryLength <= ocr3_1types.MaxMaxQueryLength) { - err = errors.Join(err, fmt.Errorf("MaxQueryLength (%v) out of range. Should be between 0 and %v", limits.MaxQueryLength, ocr3_1types.MaxMaxQueryLength)) + if !(0 <= limits.MaxQueryBytes && limits.MaxQueryBytes <= ocr3_1types.MaxMaxQueryBytes) { + err = errors.Join(err, fmt.Errorf("MaxQueryBytes (%v) out of range. Should be between 0 and %v", limits.MaxQueryBytes, ocr3_1types.MaxMaxQueryBytes)) } - if !(0 <= limits.MaxObservationLength && limits.MaxObservationLength <= ocr3_1types.MaxMaxObservationLength) { - err = errors.Join(err, fmt.Errorf("MaxObservationLength (%v) out of range. Should be between 0 and %v", limits.MaxObservationLength, ocr3_1types.MaxMaxObservationLength)) + if !(0 <= limits.MaxObservationBytes && limits.MaxObservationBytes <= ocr3_1types.MaxMaxObservationBytes) { + err = errors.Join(err, fmt.Errorf("MaxObservationBytes (%v) out of range. Should be between 0 and %v", limits.MaxObservationBytes, ocr3_1types.MaxMaxObservationBytes)) } - if !(0 <= limits.MaxReportLength && limits.MaxReportLength <= ocr3_1types.MaxMaxReportLength) { - err = errors.Join(err, fmt.Errorf("MaxReportLength (%v) out of range. Should be between 0 and %v", limits.MaxReportLength, ocr3_1types.MaxMaxReportLength)) + if !(0 <= limits.MaxReportBytes && limits.MaxReportBytes <= ocr3_1types.MaxMaxReportBytes) { + err = errors.Join(err, fmt.Errorf("MaxReportBytes (%v) out of range. Should be between 0 and %v", limits.MaxReportBytes, ocr3_1types.MaxMaxReportBytes)) } - if !(0 <= limits.MaxReportsPlusPrecursorLength && limits.MaxReportsPlusPrecursorLength <= ocr3_1types.MaxMaxReportsPlusPrecursorLength) { - err = errors.Join(err, fmt.Errorf("MaxReportInfoLength (%v) out of range. Should be between 0 and %v", limits.MaxReportsPlusPrecursorLength, ocr3_1types.MaxMaxReportsPlusPrecursorLength)) + if !(0 <= limits.MaxReportsPlusPrecursorBytes && limits.MaxReportsPlusPrecursorBytes <= ocr3_1types.MaxMaxReportsPlusPrecursorBytes) { + err = errors.Join(err, fmt.Errorf("MaxReportsPlusPrecursorBytes (%v) out of range. Should be between 0 and %v", limits.MaxReportsPlusPrecursorBytes, ocr3_1types.MaxMaxReportsPlusPrecursorBytes)) } if !(0 <= limits.MaxReportCount && limits.MaxReportCount <= ocr3_1types.MaxMaxReportCount) { err = errors.Join(err, fmt.Errorf("MaxReportCount (%v) out of range. Should be between 0 and %v", limits.MaxReportCount, ocr3_1types.MaxMaxReportCount)) } - if !(0 <= limits.MaxKeyValueModifiedKeysPlusValuesLength && limits.MaxKeyValueModifiedKeysPlusValuesLength <= ocr3_1types.MaxMaxKeyValueModifiedKeysPlusValuesLength) { - err = errors.Join(err, fmt.Errorf("MaxKeyValueModifiedKeysPlusValuesLength (%v) out of range. Should be between 0 and %v", limits.MaxKeyValueModifiedKeysPlusValuesLength, ocr3_1types.MaxMaxKeyValueModifiedKeysPlusValuesLength)) + if !(0 <= limits.MaxKeyValueModifiedKeys && limits.MaxKeyValueModifiedKeys <= ocr3_1types.MaxMaxKeyValueModifiedKeys) { + err = errors.Join(err, fmt.Errorf("MaxKeyValueModifiedKeys (%v) out of range. Should be between 0 and %v", limits.MaxKeyValueModifiedKeys, ocr3_1types.MaxMaxKeyValueModifiedKeys)) + } + if !(0 <= limits.MaxKeyValueModifiedKeysPlusValuesBytes && limits.MaxKeyValueModifiedKeysPlusValuesBytes <= ocr3_1types.MaxMaxKeyValueModifiedKeysPlusValuesBytes) { + err = errors.Join(err, fmt.Errorf("MaxKeyValueModifiedKeysPlusValuesBytes (%v) out of range. Should be between 0 and %v", limits.MaxKeyValueModifiedKeysPlusValuesBytes, ocr3_1types.MaxMaxKeyValueModifiedKeysPlusValuesBytes)) } - if !(0 <= limits.MaxBlobPayloadLength && limits.MaxBlobPayloadLength <= ocr3_1types.MaxMaxBlobPayloadLength) { - err = errors.Join(err, fmt.Errorf("MaxBlobPayloadLength (%v) out of range. Should be between 0 and %v", limits.MaxBlobPayloadLength, ocr3_1types.MaxMaxBlobPayloadLength)) + if !(0 <= limits.MaxBlobPayloadBytes && limits.MaxBlobPayloadBytes <= ocr3_1types.MaxMaxBlobPayloadBytes) { + err = errors.Join(err, fmt.Errorf("MaxBlobPayloadBytes (%v) out of range. Should be between 0 and %v", limits.MaxBlobPayloadBytes, ocr3_1types.MaxMaxBlobPayloadBytes)) } return err } diff --git a/offchainreporting2plus/internal/ocr3_1/blobtypes/serialization.go b/offchainreporting2plus/internal/ocr3_1/blobtypes/serialization.go index 7c239e5f..9dc2c315 100644 --- a/offchainreporting2plus/internal/ocr3_1/blobtypes/serialization.go +++ b/offchainreporting2plus/internal/ocr3_1/blobtypes/serialization.go @@ -6,6 +6,7 @@ import ( "fmt" "github.com/smartcontractkit/libocr/commontypes" + "github.com/smartcontractkit/libocr/internal/mt" "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/ocr3_1/blobtypes/serialization" "google.golang.org/protobuf/proto" ) @@ -15,11 +16,6 @@ var _ encoding.BinaryAppender = LightCertifiedBlob{} var _ encoding.BinaryUnmarshaler = &LightCertifiedBlob{} func (lc LightCertifiedBlob) AppendBinary(b []byte) ([]byte, error) { - pbChunkDigests := make([][]byte, 0, len(lc.ChunkDigests)) - for _, digest := range lc.ChunkDigests { - pbChunkDigests = append(pbChunkDigests, digest[:]) - } - pbSignatures := make([]*serialization.AttributedBlobAvailabilitySignature, 0, len(lc.AttributedBlobAvailabilitySignatures)) for _, sig := range lc.AttributedBlobAvailabilitySignatures { pbSignatures = append(pbSignatures, serialization.NewAttributedBlobAvailabilitySignature( @@ -29,7 +25,7 @@ func (lc LightCertifiedBlob) AppendBinary(b []byte) ([]byte, error) { } pbLightCertifiedBlob := serialization.NewLightCertifiedBlob( - pbChunkDigests, + lc.ChunkDigestsRoot[:], lc.PayloadLength, lc.ExpirySeqNr, uint32(lc.Submitter), @@ -54,15 +50,11 @@ func (lc *LightCertifiedBlob) UnmarshalBinary(data []byte) error { return fmt.Errorf("failed to unmarshal LightCertifiedBlob protobuf: %w", err) } - chunkDigests := make([]BlobChunkDigest, 0, len(pbLightCertifiedBlob.ChunkDigests)) - for _, digest := range pbLightCertifiedBlob.ChunkDigests { - if len(digest) != len(BlobChunkDigest{}) { - return fmt.Errorf("invalid chunk digest length: expected %d bytes, got %d", len(BlobChunkDigest{}), len(digest)) - } - var chunkDigest BlobChunkDigest - copy(chunkDigest[:], digest) - chunkDigests = append(chunkDigests, chunkDigest) + var chunkDigestsRoot mt.Digest + if len(pbLightCertifiedBlob.ChunkDigestsRoot) != len(mt.Digest{}) { + return fmt.Errorf("invalid chunk digests root length: expected %d bytes, got %d", len(mt.Digest{}), len(pbLightCertifiedBlob.ChunkDigestsRoot)) } + copy(chunkDigestsRoot[:], pbLightCertifiedBlob.ChunkDigestsRoot) signatures := make([]AttributedBlobAvailabilitySignature, 0, len(pbLightCertifiedBlob.AttributedBlobAvailabilitySignatures)) for _, sig := range pbLightCertifiedBlob.AttributedBlobAvailabilitySignatures { @@ -76,7 +68,7 @@ func (lc *LightCertifiedBlob) UnmarshalBinary(data []byte) error { } *lc = LightCertifiedBlob{ - chunkDigests, + chunkDigestsRoot, pbLightCertifiedBlob.PayloadLength, pbLightCertifiedBlob.ExpirySeqNr, commontypes.OracleID(pbLightCertifiedBlob.Submitter), diff --git a/offchainreporting2plus/internal/ocr3_1/blobtypes/serialization/offchainreporting3_1_blobs.pb.go b/offchainreporting2plus/internal/ocr3_1/blobtypes/serialization/offchainreporting3_1_blobs.pb.go index 18df5174..05383c38 100644 --- a/offchainreporting2plus/internal/ocr3_1/blobtypes/serialization/offchainreporting3_1_blobs.pb.go +++ b/offchainreporting2plus/internal/ocr3_1/blobtypes/serialization/offchainreporting3_1_blobs.pb.go @@ -25,7 +25,7 @@ type LightCertifiedBlob struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - ChunkDigests [][]byte `protobuf:"bytes,1,rep,name=chunk_digests,json=chunkDigests,proto3" json:"chunk_digests,omitempty"` + ChunkDigestsRoot []byte `protobuf:"bytes,1,opt,name=chunk_digests_root,json=chunkDigestsRoot,proto3" json:"chunk_digests_root,omitempty"` PayloadLength uint64 `protobuf:"varint,2,opt,name=payload_length,json=payloadLength,proto3" json:"payload_length,omitempty"` ExpirySeqNr uint64 `protobuf:"varint,3,opt,name=expiry_seq_nr,json=expirySeqNr,proto3" json:"expiry_seq_nr,omitempty"` Submitter uint32 `protobuf:"varint,4,opt,name=submitter,proto3" json:"submitter,omitempty"` @@ -64,9 +64,9 @@ func (*LightCertifiedBlob) Descriptor() ([]byte, []int) { return file_offchainreporting3_1_blobs_proto_rawDescGZIP(), []int{0} } -func (x *LightCertifiedBlob) GetChunkDigests() [][]byte { +func (x *LightCertifiedBlob) GetChunkDigestsRoot() []byte { if x != nil { - return x.ChunkDigests + return x.ChunkDigestsRoot } return nil } @@ -160,34 +160,35 @@ var file_offchainreporting3_1_blobs_proto_rawDesc = []byte{ 0x0a, 0x20, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x5f, 0x62, 0x6c, 0x6f, 0x62, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x14, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, - 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x22, 0xb5, 0x02, 0x0a, 0x12, 0x4c, 0x69, 0x67, + 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x22, 0xbe, 0x02, 0x0a, 0x12, 0x4c, 0x69, 0x67, 0x68, 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x42, 0x6c, 0x6f, 0x62, 0x12, - 0x23, 0x0a, 0x0d, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0c, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x44, 0x69, 0x67, - 0x65, 0x73, 0x74, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, - 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x70, 0x61, - 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x12, 0x22, 0x0a, 0x0d, 0x65, - 0x78, 0x70, 0x69, 0x72, 0x79, 0x5f, 0x73, 0x65, 0x71, 0x5f, 0x6e, 0x72, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x0b, 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, 0x53, 0x65, 0x71, 0x4e, 0x72, 0x12, - 0x1c, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x09, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x72, 0x12, 0x90, 0x01, - 0x0a, 0x27, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x64, 0x5f, 0x62, 0x6c, 0x6f, - 0x62, 0x5f, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x5f, 0x73, - 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x39, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, - 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, - 0x64, 0x42, 0x6c, 0x6f, 0x62, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, - 0x79, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x24, 0x61, 0x74, 0x74, 0x72, - 0x69, 0x62, 0x75, 0x74, 0x65, 0x64, 0x42, 0x6c, 0x6f, 0x62, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, - 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, - 0x22, 0x5b, 0x0a, 0x23, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x64, 0x42, 0x6c, - 0x6f, 0x62, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x53, 0x69, - 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, - 0x74, 0x75, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, - 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x42, 0x11, 0x5a, - 0x0f, 0x2e, 0x3b, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x2c, 0x0a, 0x12, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, + 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, 0x63, 0x68, 0x75, + 0x6e, 0x6b, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x25, 0x0a, + 0x0e, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x4c, 0x65, + 0x6e, 0x67, 0x74, 0x68, 0x12, 0x22, 0x0a, 0x0d, 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, 0x5f, 0x73, + 0x65, 0x71, 0x5f, 0x6e, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x65, 0x78, 0x70, + 0x69, 0x72, 0x79, 0x53, 0x65, 0x71, 0x4e, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x6d, + 0x69, 0x74, 0x74, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x73, 0x75, 0x62, + 0x6d, 0x69, 0x74, 0x74, 0x65, 0x72, 0x12, 0x90, 0x01, 0x0a, 0x27, 0x61, 0x74, 0x74, 0x72, 0x69, + 0x62, 0x75, 0x74, 0x65, 0x64, 0x5f, 0x62, 0x6c, 0x6f, 0x62, 0x5f, 0x61, 0x76, 0x61, 0x69, 0x6c, + 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, + 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, + 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, + 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x64, 0x42, 0x6c, 0x6f, 0x62, 0x41, 0x76, + 0x61, 0x69, 0x6c, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, + 0x75, 0x72, 0x65, 0x52, 0x24, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x64, 0x42, + 0x6c, 0x6f, 0x62, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x53, + 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x22, 0x5b, 0x0a, 0x23, 0x41, 0x74, 0x74, + 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x64, 0x42, 0x6c, 0x6f, 0x62, 0x41, 0x76, 0x61, 0x69, 0x6c, + 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, + 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x16, + 0x0a, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, + 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x42, 0x11, 0x5a, 0x0f, 0x2e, 0x3b, 0x73, 0x65, 0x72, 0x69, + 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, } var ( diff --git a/offchainreporting2plus/internal/ocr3_1/blobtypes/serialization/serialization.go b/offchainreporting2plus/internal/ocr3_1/blobtypes/serialization/serialization.go index 54ca5753..ea059702 100644 --- a/offchainreporting2plus/internal/ocr3_1/blobtypes/serialization/serialization.go +++ b/offchainreporting2plus/internal/ocr3_1/blobtypes/serialization/serialization.go @@ -20,7 +20,7 @@ func NewAttributedBlobAvailabilitySignature( } func NewLightCertifiedBlob( - chunkDigests [][]byte, + chunkDigestsRoot []byte, payloadLength uint64, expirySeqNr uint64, submitter uint32, @@ -32,7 +32,7 @@ func NewLightCertifiedBlob( 0, nil, // fields - chunkDigests, + chunkDigestsRoot, payloadLength, expirySeqNr, submitter, diff --git a/offchainreporting2plus/internal/ocr3_1/blobtypes/types.go b/offchainreporting2plus/internal/ocr3_1/blobtypes/types.go index f74a9963..42c89a59 100644 --- a/offchainreporting2plus/internal/ocr3_1/blobtypes/types.go +++ b/offchainreporting2plus/internal/ocr3_1/blobtypes/types.go @@ -9,6 +9,7 @@ import ( "hash" "github.com/smartcontractkit/libocr/commontypes" + "github.com/smartcontractkit/libocr/internal/mt" "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config" "github.com/smartcontractkit/libocr/offchainreporting2plus/types" ) @@ -40,6 +41,28 @@ func MakeBlobChunkDigest(chunk []byte) BlobChunkDigest { return result } +type BlobChunkDigestsRoot = mt.Digest + +func chunkDigestsToLeafPreimages(chunkDigests []BlobChunkDigest) [][]byte { + chunkDigestsLeafPreimages := make([][]byte, 0, len(chunkDigests)) + for _, chunkDigest := range chunkDigests { + chunkDigestsLeafPreimages = append(chunkDigestsLeafPreimages, chunkDigest[:]) + } + return chunkDigestsLeafPreimages +} + +func MakeBlobChunkDigestsRoot(chunkDigests []BlobChunkDigest) BlobChunkDigestsRoot { + return mt.Root(chunkDigestsToLeafPreimages(chunkDigests)) +} + +func ProveBlobChunkDigest(chunkDigests []BlobChunkDigest, index uint64) ([]mt.Digest, error) { + return mt.Prove(chunkDigestsToLeafPreimages(chunkDigests), index) +} + +func VerifyBlobChunkDigest(chunkDigestsRoot BlobChunkDigestsRoot, index uint64, chunkDigest BlobChunkDigest, proof []mt.Digest) error { + return mt.Verify(chunkDigestsRoot, index, chunkDigest[:], proof) +} + type BlobDigest [32]byte var _ fmt.Stringer = BlobDigest{} @@ -50,7 +73,7 @@ func (bd BlobDigest) String() string { func MakeBlobDigest( configDigest types.ConfigDigest, - chunkDigests []BlobChunkDigest, + chunkDigestsRoot mt.Digest, payloadLength uint64, expirySeqNr uint64, submitter commontypes.OracleID, @@ -59,11 +82,7 @@ func MakeBlobDigest( _, _ = h.Write(configDigest[:]) - _ = binary.Write(h, binary.BigEndian, uint64(len(chunkDigests))) - for _, chunkDigest := range chunkDigests { - - _, _ = h.Write(chunkDigest[:]) - } + _, _ = h.Write(chunkDigestsRoot[:]) _ = binary.Write(h, binary.BigEndian, payloadLength) @@ -123,10 +142,10 @@ type AttributedBlobAvailabilitySignature struct { } type LightCertifiedBlob struct { - ChunkDigests []BlobChunkDigest - PayloadLength uint64 - ExpirySeqNr uint64 - Submitter commontypes.OracleID + ChunkDigestsRoot mt.Digest + PayloadLength uint64 + ExpirySeqNr uint64 + Submitter commontypes.OracleID AttributedBlobAvailabilitySignatures []AttributedBlobAvailabilitySignature } @@ -134,16 +153,16 @@ type LightCertifiedBlob struct { func (lc *LightCertifiedBlob) Verify( configDigest types.ConfigDigest, oracleIdentities []config.OracleIdentity, - fPlusOneSize int, byzQuorumSize int, + n int, ) error { - if !(fPlusOneSize <= len(lc.AttributedBlobAvailabilitySignatures) && len(lc.AttributedBlobAvailabilitySignatures) <= byzQuorumSize) { - return fmt.Errorf("wrong number of signatures, expected in range [%d, %d] for quorum but got %d", fPlusOneSize, byzQuorumSize, len(lc.AttributedBlobAvailabilitySignatures)) + if !(byzQuorumSize <= len(lc.AttributedBlobAvailabilitySignatures) && len(lc.AttributedBlobAvailabilitySignatures) <= n) { + return fmt.Errorf("wrong number of signatures, expected in range [%d, %d] for quorum but got %d", byzQuorumSize, n, len(lc.AttributedBlobAvailabilitySignatures)) } blobDigest := MakeBlobDigest( configDigest, - lc.ChunkDigests, + lc.ChunkDigestsRoot, lc.PayloadLength, lc.ExpirySeqNr, lc.Submitter, diff --git a/offchainreporting2plus/internal/ocr3_1/maxmaxserializationlimits/max_max_serialization_limits.go b/offchainreporting2plus/internal/ocr3_1/maxmaxserializationlimits/max_max_serialization_limits.go new file mode 100644 index 00000000..6ddf7d3d --- /dev/null +++ b/offchainreporting2plus/internal/ocr3_1/maxmaxserializationlimits/max_max_serialization_limits.go @@ -0,0 +1,14 @@ +package maxmaxserializationlimits + +const ( + MaxMaxEpochStartRequestBytes = 2265 + MaxMaxEpochStartBytes = 4825 + MaxMaxReportsPlusPrecursorRequestBytes = 18 + MaxMaxReportsPlusPrecursorBytes = 6815772 + MaxMaxBlockSyncRequestBytes = 32 + MaxMaxBlockSyncResponseBytes = 27371305 + MaxMaxTreeSyncChunkRequestBytes = 106 + MaxMaxTreeSyncChunkResponseBytes = 65049225 + MaxMaxBlobChunkRequestBytes = 62 + MaxMaxBlobChunkResponseBytes = 13000163 +) diff --git a/offchainreporting2plus/internal/ocr3_1/protocol/blob_endpoint.go b/offchainreporting2plus/internal/ocr3_1/protocol/blob_endpoint.go index 6770e4dc..a38ec59a 100644 --- a/offchainreporting2plus/internal/ocr3_1/protocol/blob_endpoint.go +++ b/offchainreporting2plus/internal/ocr3_1/protocol/blob_endpoint.go @@ -9,6 +9,14 @@ import ( "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3_1types" ) +// BlobEndpointWrapper enables deferred initialization of a BlobEndpoint. The +// plugin expects a BlobBroadcastFetcher instance as argument to +// NewReportingPlugin, which is called in managed_ocr3_1_oracle.go. The actual +// BlobEndpoint is only constructed later in RunOracle, where the blob exchange +// protocol is started. RunOracle then initializes the wrapper with the +// BlobEndpoint using setBlobEndpoint. All BlobBroadcastFetcher methods of +// BlobEndpointWrapper will error until proper initialization through +// setBlobEndpoint. type BlobEndpointWrapper struct { mu sync.Mutex wrapped *BlobEndpoint diff --git a/offchainreporting2plus/internal/ocr3_1/protocol/blob_exchange.go b/offchainreporting2plus/internal/ocr3_1/protocol/blob_exchange.go index b0a67cc6..98f599e1 100644 --- a/offchainreporting2plus/internal/ocr3_1/protocol/blob_exchange.go +++ b/offchainreporting2plus/internal/ocr3_1/protocol/blob_exchange.go @@ -3,7 +3,6 @@ package protocol import ( "context" "fmt" - "math/rand/v2" "slices" "time" @@ -11,8 +10,9 @@ import ( "github.com/smartcontractkit/libocr/commontypes" "github.com/smartcontractkit/libocr/internal/byzquorum" "github.com/smartcontractkit/libocr/internal/loghelper" + "github.com/smartcontractkit/libocr/internal/mt" "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/common/scheduler" - "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3config" + "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config" "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/ocr3_1/blobtypes" "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/ocr3_1/protocol/requestergadget" "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3_1types" @@ -29,7 +29,7 @@ func RunBlobExchange[RI any]( chBlobBroadcastRequest <-chan blobBroadcastRequest, chBlobFetchRequest <-chan blobFetchRequest, - config ocr3config.SharedConfig, + config ocr3_1config.SharedConfig, kv KeyValueDatabase, id commontypes.OracleID, limits ocr3_1types.ReportingPluginLimits, @@ -64,7 +64,7 @@ func makeBlobExchangeState[RI any]( chBlobBroadcastRequest <-chan blobBroadcastRequest, chBlobFetchRequest <-chan blobFetchRequest, - config ocr3config.SharedConfig, + config ocr3_1config.SharedConfig, kv KeyValueDatabase, id commontypes.OracleID, limits ocr3_1types.ReportingPluginLimits, @@ -77,7 +77,9 @@ func makeBlobExchangeState[RI any]( broadcastGraceTimeoutScheduler *scheduler.Scheduler[EventBlobBroadcastGraceTimeout[RI]], ) *blobExchangeState[RI] { - tStopExpiredBlobFetches := time.After(DeltaStopExpiredBlobFetches) + offerLogTapers := make([]loghelper.LogarithmicTaper, config.N()) + + tStopExpiredBlobFetchOrBroadcast := time.After(DeltaStopExpiredBlobFetchOrBroadcast) bex := &blobExchangeState[RI]{ ctx, @@ -96,6 +98,8 @@ func makeBlobExchangeState[RI any]( limits, localConfig, logger.MakeUpdated(commontypes.LogFields{"proto": "bex"}), + offerLogTapers, + newBlobExchangeMetrics(metricsRegisterer, logger), netSender, offchainKeyring, telemetrySender, @@ -104,14 +108,14 @@ func makeBlobExchangeState[RI any]( nil, // must be filled right below nil, // must be filled right below - tStopExpiredBlobFetches, + tStopExpiredBlobFetchOrBroadcast, make(map[BlobDigest]*blob), } offerRequesterGadget := requestergadget.NewRequesterGadget[blobOfferItem]( config.N(), - DeltaBlobOfferBroadcast, + config.GetDeltaBlobOfferMinRequestToSameOracleInterval(), bex.trySendBlobOffer, bex.getPendingBlobOffers, bex.getBlobOfferSeeders, @@ -120,7 +124,7 @@ func makeBlobExchangeState[RI any]( chunkRequesterGadget := requestergadget.NewRequesterGadget[blobChunkId]( config.N(), - DeltaBlobChunkRequest, + config.GetDeltaBlobChunkMinRequestToSameOracleInterval(), bex.trySendBlobChunkRequest, bex.getPendingBlobChunks, bex.getBlobChunkSeeders, @@ -140,26 +144,26 @@ func (bex *blobExchangeState[RI]) trySendBlobChunkRequest(id blobChunkId, seeder return nil, false } + timeout := bex.config.GetDeltaBlobChunkResponseTimeout() + bex.logger.Debug("sending MessageBlobChunkRequest", commontypes.LogFields{ "blobDigest": id.blobDigest, "chunkIndex": id.chunkIndex, + "timeout": timeout, "seeder": seeder, }) - chunkSize := blob.getBlobChunkSize(id.chunkIndex) - expiryTimestamp := time.Now().Add(blobChunkRequestExpiration(chunkSize)) + requestInfo := &types.RequestInfo{ + time.Now().Add(timeout), + } bex.netSender.SendTo(MessageBlobChunkRequest[RI]{ - nil, - &MessageBlobChunkRequestInfo{ - expiryTimestamp, - }, + types.EmptyRequestHandleForOutboundRequest, + requestInfo, id.blobDigest, id.chunkIndex, }, seeder) - return &requestergadget.RequestInfo{ - expiryTimestamp, - }, true + return requestInfo, true } func (bex *blobExchangeState[RI]) getBlobDigestsOrderedByTimeWhenAdded() []BlobDigest { @@ -228,29 +232,29 @@ func (bex *blobExchangeState[RI]) trySendBlobOffer(item blobOfferItem, seeder co return nil, false } + timeout := bex.config.GetDeltaBlobOfferResponseTimeout() + bex.logger.Trace("sending MessageBlobOffer", commontypes.LogFields{ - "blobDigest": item.blobDigest, - "chunkDigests": blob.chunkDigests, - "payloadLength": blob.payloadLength, - "expirySeqNr": blob.expirySeqNr, - "to": seeder, + "blobDigest": item.blobDigest, + "chunkDigestsRoot": blob.chunkDigestsRoot, + "payloadLength": blob.payloadLength, + "expirySeqNr": blob.expirySeqNr, + "timeout": timeout, + "to": seeder, }) - expiryTimestamp := time.Now().Add(blobOfferBroadcastExpiration(blob.payloadLength)) - + requestInfo := &types.RequestInfo{ + time.Now().Add(timeout), + } bex.netSender.SendTo(MessageBlobOffer[RI]{ - nil, - &MessageBlobOfferRequestInfo{ - expiryTimestamp, - }, - blob.chunkDigests, + types.EmptyRequestHandleForOutboundRequest, + requestInfo, + blob.chunkDigestsRoot, blob.payloadLength, blob.expirySeqNr, }, seeder) - return &requestergadget.RequestInfo{ - expiryTimestamp, - }, true + return requestInfo, true } func (bex *blobExchangeState[RI]) getPendingBlobOffers() []blobOfferItem { @@ -280,51 +284,18 @@ func (bex *blobExchangeState[RI]) getBlobOfferSeeders(item blobOfferItem) map[co } const ( - rateBytesPerSecond = 10 * 1024 * 1024 // 10 MiB/s - latencyOverhead = 1 * time.Second - - // DeltaBlobChunkRequest denotes the minimum duration between sending two - // MessageBlobChunkRequest messages to a particular oracle. - DeltaBlobChunkRequest = 10 * time.Millisecond - - // DeltaBlobOfferBroadcast denotes the minimum duration between sending two - // MessageBlobOffer messages to a particular oracle. - DeltaBlobOfferBroadcast = 10 * time.Millisecond - - // DeltaBlobBroadcastGrace denotes the duration that we will wait after - // receiving minSigners valid accepting MessageBlobOfferResponse messages, - // to give a last chance to straggling oracles to send us a - // MessageBlobOfferResponse. - DeltaBlobBroadcastGrace = 100 * time.Millisecond - - // DeltaStopExpiredBlobFetches denotes the interval with which we check for - // in-progress blob fetches for blobs that might have expired, and mark them - // as expired and/or send reject MessageBlobOfferResponse to the submitter - // if appropriate. - DeltaStopExpiredBlobFetches = 5 * time.Second + // If we receive an offer from an oracle while we have at least this many + // concurrent blob fetches with pending offer responses to the same oracle, + // we will reject the offer. + maxOwedOfferResponsesPerOracle = 10 + + // DeltaStopExpiredBlobFetchOrBroadcast denotes the interval with which we + // check for in-progress blob broadcasts and fetches for blobs that might + // have expired, and mark them as expired and/or send reject + // MessageBlobOfferResponse to the submitter if appropriate. + DeltaStopExpiredBlobFetchOrBroadcast = 5 * time.Second ) -func transmitDataDuration(rateBytesPerSecond int, size uint64) time.Duration { - secs := float64(size) / float64(rateBytesPerSecond) - return time.Duration(secs * float64(time.Second)) -} - -func blobChunkRequestExpiration(chunkSize uint64) time.Duration { - return latencyOverhead + transmitDataDuration(rateBytesPerSecond, chunkSize) -} - -func blobOfferBroadcastExpiration(payloadLength uint64) time.Duration { - const latencyPerChunk = DeltaBlobChunkRequest - - expiration := latencyOverhead - for i := uint64(0); i < payloadLength; i += BlobChunkSize { - chunkSize := min(BlobChunkSize, payloadLength-i) - expiration += latencyPerChunk - expiration += transmitDataDuration(rateBytesPerSecond, chunkSize) - } - return expiration -} - type blobBroadcastRequest struct { payload []byte expirySeqNr uint64 @@ -375,12 +346,14 @@ type blobExchangeState[RI any] struct { chBlobBroadcastRequest <-chan blobBroadcastRequest chBlobFetchRequest <-chan blobFetchRequest - config ocr3config.SharedConfig + config ocr3_1config.SharedConfig kv KeyValueDatabase id commontypes.OracleID limits ocr3_1types.ReportingPluginLimits localConfig types.LocalConfig logger loghelper.LoggerWithContext + offerLogTapers []loghelper.LogarithmicTaper + metrics *blobExchangeMetrics netSender NetworkSender[RI] offchainKeyring types.OffchainKeyring telemetrySender TelemetrySender @@ -390,8 +363,9 @@ type blobExchangeState[RI any] struct { offerRequesterGadget *requestergadget.RequesterGadget[blobOfferItem] // blob fetch - chunkRequesterGadget *requestergadget.RequesterGadget[blobChunkId] - tStopExpiredBlobFetches <-chan time.Time + chunkRequesterGadget *requestergadget.RequesterGadget[blobChunkId] + + tStopExpiredBlobBroadcastOrFetch <-chan time.Time blobs map[BlobDigest]*blob } @@ -406,10 +380,8 @@ type blobChunkId struct { chunkIndex uint64 } -const BlobChunkSize = 1 << 22 // 4MiB - -func numChunks(payloadLength uint64) uint64 { - return (payloadLength + BlobChunkSize - 1) / BlobChunkSize +func numChunks(payloadLength uint64, blobChunkSize int) uint64 { + return (payloadLength + uint64(blobChunkSize) - 1) / uint64(blobChunkSize) } type blobFetchMeta struct { @@ -438,6 +410,7 @@ const ( blobBroadcastPhaseAcceptedGrace blobBroadcastPhase = "acceptedGrace" blobBroadcastPhaseAccepted blobBroadcastPhase = "accepted" blobBroadcastPhaseRejected blobBroadcastPhase = "rejected" + blobBroadcastPhaseExpired blobBroadcastPhase = "expired" ) type blobBroadcastMeta struct { @@ -496,19 +469,17 @@ type blob struct { broadcast *blobBroadcastMeta fetch *blobFetchMeta - chunkDigests []BlobChunkDigest - chunkHaves []bool + chunkDigestsRoot mt.Digest + chunkDigests []BlobChunkDigest + chunkHaves []bool payloadLength uint64 expirySeqNr uint64 submitter commontypes.OracleID } -func (b *blob) getBlobChunkSize(chunkIndex uint64) uint64 { - if chunkIndex == uint64(len(b.chunkDigests))-1 { - return b.payloadLength % BlobChunkSize - } - return BlobChunkSize +func (b *blob) weOweOfferResponse() bool { + return b.fetch != nil && b.fetch.exchange != nil && !b.fetch.exchange.weSentOfferResponse } func (b *blob) haveAllChunks() bool { @@ -553,8 +524,8 @@ func (bex *blobExchangeState[RI]) run() { case <-bex.chunkRequesterGadget.Ticker(): bex.chunkRequesterGadget.Tick() - case <-bex.tStopExpiredBlobFetches: - bex.eventTStopExpiredBlobFetches() + case <-bex.tStopExpiredBlobBroadcastOrFetch: + bex.eventTStopExpiredBlobBroadcastOrFetch() case <-chDone: } @@ -564,7 +535,7 @@ func (bex *blobExchangeState[RI]) run() { case <-chDone: bex.logger.Info("BlobExchange: winding down", nil) bex.subs.Wait() - // bex.metrics.Close() + bex.metrics.Close() bex.logger.Info("BlobExchange: exiting", nil) return default: @@ -572,14 +543,14 @@ func (bex *blobExchangeState[RI]) run() { } } -func (bex *blobExchangeState[RI]) eventTStopExpiredBlobFetches() { +func (bex *blobExchangeState[RI]) eventTStopExpiredBlobBroadcastOrFetch() { defer func() { - bex.tStopExpiredBlobFetches = time.After(DeltaStopExpiredBlobFetches) + bex.tStopExpiredBlobBroadcastOrFetch = time.After(DeltaStopExpiredBlobFetchOrBroadcast) }() tx, err := bex.kv.NewReadTransactionUnchecked() if err != nil { - bex.logger.Error("failed to create read transaction for eventTStopExpiredBlobFetches", commontypes.LogFields{ + bex.logger.Error("failed to create read transaction for eventTStopExpiredBlobBroadcastOrFetch", commontypes.LogFields{ "error": err, }) return @@ -588,62 +559,151 @@ func (bex *blobExchangeState[RI]) eventTStopExpiredBlobFetches() { highestCommittedSeqNr, err := tx.ReadHighestCommittedSeqNr() if err != nil { - bex.logger.Error("failed to read highest committed seq nr for eventTStopExpiredBlobFetches", commontypes.LogFields{ + bex.logger.Error("failed to read highest committed seq nr for eventTStopExpiredBlobBroadcastOrFetch", commontypes.LogFields{ "error": err, }) return } for blobDigest, blob := range bex.blobs { - fetch := blob.fetch - if fetch == nil { - continue - } - if fetch.expired || blob.haveAllChunks() { + if !hasBlobExpired(blob.expirySeqNr, highestCommittedSeqNr) { continue } - if !hasBlobExpired(blob.expirySeqNr, highestCommittedSeqNr) { + broadcastPending := blob.broadcast != nil && blob.broadcast.phase == blobBroadcastPhaseOffering + fetchPending := blob.fetch != nil && !blob.fetch.expired && !blob.haveAllChunks() + + if !(broadcastPending || fetchPending) { continue } - bex.logger.Debug("stopping expired blob fetch", commontypes.LogFields{ + bex.logger.Debug("stopping expired blob broadcast or fetch", commontypes.LogFields{ "blobDigest": blobDigest, "expirySeqNr": blob.expirySeqNr, "highestCommittedSeqNr": highestCommittedSeqNr, "submitter": blob.submitter, + "fetchPending": fetchPending, + "broadcastPending": broadcastPending, }) - if fetch.exchange != nil { - bex.sendBlobOfferResponseRejecting(blobDigest, blob.submitter, fetch.exchange.latestOfferRequestHandle) - fetch.exchange.weServiced() + if broadcastPending { + broadcast := blob.broadcast + broadcast.phase = blobBroadcastPhaseExpired + close(broadcast.chNotify) } - fetch.expired = true - close(fetch.chNotify) + if fetchPending { + fetch := blob.fetch + if fetch.exchange != nil { + bex.sendBlobOfferResponseRejecting(blobDigest, blob.submitter, fetch.exchange.latestOfferRequestHandle) + fetch.exchange.weServiced() + } + + fetch.expired = true + close(fetch.chNotify) + } if blob.prunable() { + bex.metrics.blobsInProgress.Dec() delete(bex.blobs, blobDigest) } } } +func (bex *blobExchangeState[RI]) allowBlobOfferBasedOnOwedOfferResponsesBudget(sender commontypes.OracleID) error { + countOwedOfferResponses := 0 + for _, blob := range bex.blobs { + if blob.submitter != sender { + continue + } + if !blob.weOweOfferResponse() { + continue + } + countOwedOfferResponses++ + } + + if countOwedOfferResponses >= maxOwedOfferResponsesPerOracle { + return fmt.Errorf("too many pending offer responses for submitter, have %d, max %d", countOwedOfferResponses, maxOwedOfferResponsesPerOracle) + } + + return nil +} + +func (bex *blobExchangeState[RI]) allowBlobOfferBasedOnQuotaStats(offer MessageBlobOffer[RI], submitter commontypes.OracleID) error { + tx, err := bex.kv.NewReadTransactionUnchecked() + if err != nil { + return fmt.Errorf("failed to create read transaction: %w", err) + } + defer tx.Discard() + + appendedQuotaStats, err := tx.ReadBlobQuotaStats(BlobQuotaStatsTypeAppended, submitter) + if err != nil { + return fmt.Errorf("failed to read blob quota stats: %w", err) + } + + reapedQuotaStats, err := tx.ReadBlobQuotaStats(BlobQuotaStatsTypeReaped, submitter) + if err != nil { + return fmt.Errorf("failed to read blob quota stats: %w", err) + } + + totalQuotaStats, ok := appendedQuotaStats.Sub(reapedQuotaStats) + if !ok { + return fmt.Errorf("overflow when subtracting reaped quota stats from appended quota stats") + } + + totalQuotaStatsIncludingOffer, ok := totalQuotaStats.Add(BlobQuotaStats{ + 1, + offer.PayloadLength, + }) + if !ok { + return fmt.Errorf("overflow when considering offer in quota stats") + } + + maxQuotaStats := BlobQuotaStats{ + uint64(bex.limits.MaxPerOracleUnexpiredBlobCount), + uint64(bex.limits.MaxPerOracleUnexpiredBlobCumulativePayloadBytes), + } + + if totalQuotaStatsIncludingOffer.Count > maxQuotaStats.Count { + return fmt.Errorf("accepting the offer would exceed our allowed per-oracle unexpired blob count, have %d, max %d", totalQuotaStats.Count, maxQuotaStats.Count) + } + + if totalQuotaStatsIncludingOffer.CumulativePayloadLength > maxQuotaStats.CumulativePayloadLength { + return fmt.Errorf("accepting the offer would exceed our allowed per-oracle unexpired blob payload length, have %d, offer is for %d, max is %d", totalQuotaStats.CumulativePayloadLength, offer.PayloadLength, maxQuotaStats.CumulativePayloadLength) + } + + return nil +} + +func (bex *blobExchangeState[RI]) allowBlobOffer(offer MessageBlobOffer[RI], submitter commontypes.OracleID) error { + if err := bex.allowBlobOfferBasedOnOwedOfferResponsesBudget(submitter); err != nil { + return err + } + + if err := bex.allowBlobOfferBasedOnQuotaStats(offer, submitter); err != nil { + return err + } + + return nil +} + func (bex *blobExchangeState[RI]) messageBlobOffer(msg MessageBlobOffer[RI], sender commontypes.OracleID) { submitter := sender blobDigest := blobtypes.MakeBlobDigest( bex.config.ConfigDigest, - msg.ChunkDigests, + msg.ChunkDigestsRoot, msg.PayloadLength, msg.ExpirySeqNr, submitter, ) - chunkHaves, err := bex.loadChunkHaves(blobDigest, msg.PayloadLength) + chunkDigests, chunkHaves, err := bex.loadChunkDigestsAndHaves(blobDigest, msg.PayloadLength) if err != nil { - bex.logger.Warn("dropping MessageBlobOffer, failed to check if we already have the payload", commontypes.LogFields{ + bex.logger.Warn("dropping MessageBlobOffer, failed to check if we already know of it", commontypes.LogFields{ "blobDigest": blobDigest, "sender": sender, + "error": err, }) return } @@ -669,13 +729,18 @@ func (bex *blobExchangeState[RI]) messageBlobOffer(msg MessageBlobOffer[RI], sen return } + offerLogTaper := &bex.offerLogTapers[sender] + // Reject if payload length exceeds maximum allowed length - if msg.PayloadLength > uint64(bex.limits.MaxBlobPayloadLength) { - bex.logger.Debug("received MessageBlobOffer with payload length that exceeds maximum allowed length, rejecting", commontypes.LogFields{ - "blobDigest": blobDigest, - "submitter": submitter, - "payloadLength": msg.PayloadLength, - "maxPayloadLength": bex.limits.MaxBlobPayloadLength, + if msg.PayloadLength > uint64(bex.limits.MaxBlobPayloadBytes) { + offerLogTaper.Trigger(func(consecutiveRejectedOffers uint64) { + bex.logger.Warn("received MessageBlobOffer with payload length that exceeds maximum allowed length, rejecting", commontypes.LogFields{ + "blobDigest": blobDigest, + "submitter": submitter, + "payloadLength": msg.PayloadLength, + "maxPayloadLength": bex.limits.MaxBlobPayloadBytes, + "consecutiveRejectedOffers": consecutiveRejectedOffers, + }) }) bex.sendBlobOfferResponseRejecting(blobDigest, submitter, msg.RequestHandle) return @@ -690,30 +755,62 @@ func (bex *blobExchangeState[RI]) messageBlobOffer(msg MessageBlobOffer[RI], sen return } if hasBlobExpired(msg.ExpirySeqNr, committedSeqNr) { - bex.logger.Debug("received MessageBlobOffer for already expired blob, rejecting", commontypes.LogFields{ - "blobDigest": blobDigest, - "submitter": submitter, - "expirySeqNr": msg.ExpirySeqNr, - "committedSeqNr": committedSeqNr, + offerLogTaper.Trigger(func(consecutiveRejectedOffers uint64) { + bex.logger.Warn("received MessageBlobOffer for already expired blob, rejecting", commontypes.LogFields{ + "blobDigest": blobDigest, + "submitter": submitter, + "expirySeqNr": msg.ExpirySeqNr, + "committedSeqNr": committedSeqNr, + "consecutiveRejectedOffers": consecutiveRejectedOffers, + }) }) bex.sendBlobOfferResponseRejecting(blobDigest, submitter, msg.RequestHandle) return } - // TODO: enforce rate limit based on sender / length + if err := bex.allowBlobOffer(msg, submitter); err != nil { - bex.logger.Debug("received MessageBlobOffer", commontypes.LogFields{ - "blobDigest": blobDigest, - "sender": sender, - "chunkDigests": msg.ChunkDigests, - "payloadLength": msg.PayloadLength, - "expirySeqNr": msg.ExpirySeqNr, + offerLogTaper.Trigger(func(consecutiveRejectedOffers uint64) { + bex.logger.Info("received MessageBlobOffer that goes over rate limits, rejecting", commontypes.LogFields{ + "blobDigest": blobDigest, + "submitter": submitter, + "reason": err, + "consecutiveRejectedOffers": consecutiveRejectedOffers, + }) + }) + bex.sendBlobOfferResponseRejecting(blobDigest, sender, msg.RequestHandle) + return + } + + offerLogTaper.Reset(func(previouslyConsecutiveRejectedOffers uint64) { + bex.logger.Info("stopped receiving offers that we keep rejecting from submitter", commontypes.LogFields{ + "submitter": submitter, + "previouslyConsecutiveRejectedOffers": previouslyConsecutiveRejectedOffers, + }) + }) + + bex.logger.Info("received MessageBlobOffer for new to us blob that we can accept", commontypes.LogFields{ + "blobDigest": blobDigest, + "sender": sender, + "chunkDigestsRoot": msg.ChunkDigestsRoot, + "payloadLength": msg.PayloadLength, + "expirySeqNr": msg.ExpirySeqNr, }) seeders := map[commontypes.OracleID]struct{}{ submitter: {}, } + if err := bex.createOrUpdateBlobMetaAndQuotaStats(blobDigest, msg.PayloadLength, msg.ExpirySeqNr, submitter); err != nil { + bex.logger.Error("failed to create or update blob meta and quota stats for MessageBlobOffer", commontypes.LogFields{ + "blobDigest": blobDigest, + "submitter": submitter, + "error": err, + }) + return + } + + bex.metrics.blobsInProgress.Inc() bex.blobs[blobDigest] = &blob{ time.Now(), nil, @@ -728,13 +825,13 @@ func (bex *blobExchangeState[RI]) messageBlobOffer(msg MessageBlobOffer[RI], sen false, }, - msg.ChunkDigests, + msg.ChunkDigestsRoot, + chunkDigests, chunkHaves, msg.PayloadLength, msg.ExpirySeqNr, submitter, } - bex.chunkRequesterGadget.PleaseRecheckPendingItems() } @@ -820,7 +917,8 @@ func (bex *blobExchangeState[RI]) messageBlobOfferResponse(msg MessageBlobOfferR } } - threshold := bex.minCertSigners() + rejectThreshold := bex.minRejectors() + acceptThreshold := bex.minCertSigners() acceptingOracles, rejectingOracles := 0, 0 for _, oracle := range broadcast.oracles { @@ -839,30 +937,32 @@ func (bex *blobExchangeState[RI]) messageBlobOfferResponse(msg MessageBlobOfferR "reject": msg.RejectOffer, "acceptingOracles": acceptingOracles, "rejectingOracles": rejectingOracles, - "threshold": threshold, + "acceptThreshold": acceptThreshold, + "rejectThreshold": rejectThreshold, }) if broadcast.phase == blobBroadcastPhaseAcceptedGrace { return } - if acceptingOracles >= threshold { + if acceptingOracles >= acceptThreshold { bex.logger.Debug("minimum number of accepting oracles reached, entering grace period", commontypes.LogFields{ "acceptingOracles": acceptingOracles, - "threshold": threshold, + "acceptThreshold": acceptThreshold, "blobDigest": msg.BlobDigest, - "gracePeriod": DeltaBlobBroadcastGrace, + "gracePeriod": bex.config.GetDeltaBlobBroadcastGrace(), }) broadcast.phase = blobBroadcastPhaseAcceptedGrace bex.broadcastGraceTimeoutScheduler.ScheduleDelay(EventBlobBroadcastGraceTimeout[RI]{ msg.BlobDigest, - }, DeltaBlobBroadcastGrace) + }, bex.config.GetDeltaBlobBroadcastGrace()) return } - if rejectingOracles >= threshold { + if rejectingOracles >= rejectThreshold { bex.logger.Warn("oracle quorum rejected our broadcast", commontypes.LogFields{ "rejectingOracles": rejectingOracles, + "rejectThreshold": rejectThreshold, "blobDigest": msg.BlobDigest, }) broadcast.phase = blobBroadcastPhaseRejected @@ -897,28 +997,18 @@ func (bex *blobExchangeState[RI]) eventBlobBroadcastGraceTimeout(ev EventBlobBro maxSigners := bex.maxCertSigners() - shuffledOracles := make([]commontypes.OracleID, 0, bex.config.N()) - for i := range bex.config.N() { - shuffledOracles = append(shuffledOracles, commontypes.OracleID(i)) - } - - rand.Shuffle(len(shuffledOracles), func(i, j int) { - shuffledOracles[i], shuffledOracles[j] = shuffledOracles[j], shuffledOracles[i] - }) - var abass []AttributedBlobAvailabilitySignature - for _, oracleID := range shuffledOracles { - oracle := broadcast.oracles[oracleID] + for oracleID, oracle := range broadcast.oracles { if oracle.weReceivedOfferResponse && oracle.weReceivedOfferResponseAccepting && len(abass) < maxSigners { abass = append(abass, AttributedBlobAvailabilitySignature{ oracle.signature, - oracleID, + commontypes.OracleID(oracleID), }) } } lcb := LightCertifiedBlob{ - blob.chunkDigests, + blob.chunkDigestsRoot, blob.payloadLength, blob.expirySeqNr, blob.submitter, @@ -1012,6 +1102,33 @@ func (bex *blobExchangeState[RI]) messageBlobChunkRequest(msg MessageBlobChunkRe return } + meta, err := tx.ReadBlobMeta(msg.BlobDigest) + if err != nil { + bex.logger.Error("failed to read blob meta for MessageBlobChunkRequest", commontypes.LogFields{ + "blobDigest": msg.BlobDigest, + "error": err, + }) + return + } + + if meta == nil { + bex.logger.Debug("dropping MessageBlobChunkRequest, blob meta does not exist", commontypes.LogFields{ + "blobDigest": msg.BlobDigest, + "sender": sender, + "chunkIndex": chunkIndex, + }) + return + } + + if slices.Contains(meta.ChunkHaves, false) { + bex.logger.Debug("dropping MessageBlobChunkRequest, we do not have all chunks", commontypes.LogFields{ + "blobDigest": msg.BlobDigest, + "sender": sender, + "chunkIndex": chunkIndex, + }) + return + } + chunk, err := tx.ReadBlobChunk(msg.BlobDigest, chunkIndex) if err != nil { bex.logger.Error("failed to read blob chunk for MessageBlobChunkRequest", commontypes.LogFields{ @@ -1025,6 +1142,17 @@ func (bex *blobExchangeState[RI]) messageBlobChunkRequest(msg MessageBlobChunkRe goAway := chunk == nil + proof, err := blobtypes.ProveBlobChunkDigest(meta.ChunkDigests, chunkIndex) + if err != nil { + bex.logger.Error("failed to prove blob chunk digest for MessageBlobChunkRequest", commontypes.LogFields{ + "blobDigest": msg.BlobDigest, + "sender": sender, + "chunkIndex": chunkIndex, + "error": err, + }) + return + } + bex.logger.Debug("sending MessageBlobChunkResponse", commontypes.LogFields{ "blobDigest": msg.BlobDigest, "chunkIndex": chunkIndex, @@ -1039,6 +1167,7 @@ func (bex *blobExchangeState[RI]) messageBlobChunkRequest(msg MessageBlobChunkRe chunkIndex, goAway, chunk, + proof, }, sender, ) @@ -1069,7 +1198,6 @@ func (bex *blobExchangeState[RI]) messageBlobChunkResponse(msg MessageBlobChunkR "blobDigest": msg.BlobDigest, "sender": sender, }) - bex.chunkRequesterGadget.MarkBadResponse(bcid, sender) return } @@ -1108,20 +1236,20 @@ func (bex *blobExchangeState[RI]) messageBlobChunkResponse(msg MessageBlobChunkR "sender": sender, "chunkIndex": chunkIndex, }) - bex.chunkRequesterGadget.MarkBadResponse(bcid, sender) return } - expectedChunkDigest := blob.chunkDigests[chunkIndex] actualChunkDigest := blobtypes.MakeBlobChunkDigest(msg.Chunk) - if expectedChunkDigest != actualChunkDigest { - bex.logger.Debug("dropping MessageBlobChunkResponse, chunk digest mismatch", commontypes.LogFields{ - "blobDigest": msg.BlobDigest, - "sender": sender, - "chunkIndex": chunkIndex, - "expectedDigest": expectedChunkDigest, - "actualDigest": actualChunkDigest, + if err := blobtypes.VerifyBlobChunkDigest(blob.chunkDigestsRoot, chunkIndex, actualChunkDigest, msg.Proof); err != nil { + bex.logger.Debug("dropping MessageBlobChunkResponse, chunk digest verification failed", commontypes.LogFields{ + "blobDigest": msg.BlobDigest, + "sender": sender, + "chunkIndex": chunkIndex, + "actualDigest": actualChunkDigest, + "chunkDigestsRoot": blob.chunkDigestsRoot, + "error": err, }) + bex.chunkRequesterGadget.MarkBadResponse(bcid, sender) return } @@ -1156,10 +1284,14 @@ func (bex *blobExchangeState[RI]) messageBlobChunkResponse(msg MessageBlobChunkR chunkHaves := slices.Clone(blob.chunkHaves) chunkHaves[chunkIndex] = true + chunkDigests := slices.Clone(blob.chunkDigests) + chunkDigests[chunkIndex] = actualChunkDigest blobMeta := BlobMeta{ blob.payloadLength, chunkHaves, + chunkDigests, blob.expirySeqNr, + blob.submitter, } err = tx.WriteBlobMeta(msg.BlobDigest, blobMeta) if err != nil { @@ -1193,6 +1325,7 @@ func (bex *blobExchangeState[RI]) messageBlobChunkResponse(msg MessageBlobChunkR } blob.chunkHaves[chunkIndex] = true + blob.chunkDigests[chunkIndex] = actualChunkDigest if !blob.haveAllChunks() { return @@ -1209,28 +1342,30 @@ func (bex *blobExchangeState[RI]) messageBlobChunkResponse(msg MessageBlobChunkR fetch.exchange.weServiced() } if blob.prunable() { + bex.metrics.blobsInProgress.Dec() delete(bex.blobs, msg.BlobDigest) } } func (bex *blobExchangeState[RI]) processBlobBroadcastRequest(req blobBroadcastRequest) { - if len(req.payload) > bex.limits.MaxBlobPayloadLength { + if len(req.payload) > bex.limits.MaxBlobPayloadBytes { req.respond(bex.ctx, blobBroadcastResponse{ LightCertifiedBlob{}, fmt.Errorf("blob payload length %d exceeds maximum allowed length %d", - len(req.payload), bex.limits.MaxBlobPayloadLength), + len(req.payload), bex.limits.MaxBlobPayloadBytes), }) return } payload := req.payload payloadLength := uint64(len(payload)) + cfgBlobChunkSize := bex.config.GetBlobChunkBytes() - chunkDigests := make([]BlobChunkDigest, 0, numChunks(payloadLength)) - chunkHaves := make([]bool, 0, numChunks(payloadLength)) + chunkDigests := make([]BlobChunkDigest, 0, numChunks(payloadLength, cfgBlobChunkSize)) + chunkHaves := make([]bool, 0, numChunks(payloadLength, cfgBlobChunkSize)) - for i, chunkIdx := 0, 0; i < len(payload); i, chunkIdx = i+BlobChunkSize, chunkIdx+1 { - payloadChunk := payload[i:min(i+BlobChunkSize, len(payload))] + for i, chunkIdx := 0, 0; i < len(payload); i, chunkIdx = i+cfgBlobChunkSize, chunkIdx+1 { + payloadChunk := payload[i:min(i+cfgBlobChunkSize, len(payload))] // prepare for offer chunkDigest := blobtypes.MakeBlobChunkDigest(payloadChunk) @@ -1243,9 +1378,11 @@ func (bex *blobExchangeState[RI]) processBlobBroadcastRequest(req blobBroadcastR expirySeqNr := req.expirySeqNr submitter := bex.id + chunkDigestsRoot := blobtypes.MakeBlobChunkDigestsRoot(chunkDigests) + blobDigest := blobtypes.MakeBlobDigest( bex.config.ConfigDigest, - chunkDigests, + chunkDigestsRoot, payloadLength, expirySeqNr, submitter, @@ -1263,12 +1400,14 @@ func (bex *blobExchangeState[RI]) processBlobBroadcastRequest(req blobBroadcastR nil, make([]blobBroadcastOracleMeta, bex.config.N()), } + } else { + existingBlob.broadcast.waiters++ } chNotifyCertAvailable = existingBlob.broadcast.chNotify } else { // if we haven't written the chunks to kv, we can't serve requests - if err := bex.writeBlob(blobDigest, payloadLength, payload, expirySeqNr); err != nil { + if err := bex.writeBlobBeforeBroadcast(blobDigest, payloadLength, payload, expirySeqNr); err != nil { req.respond(bex.ctx, blobBroadcastResponse{ LightCertifiedBlob{}, fmt.Errorf("failed to write blob: %w", err), @@ -1279,6 +1418,7 @@ func (bex *blobExchangeState[RI]) processBlobBroadcastRequest(req blobBroadcastR // write in-memory state chNotifyCertAvailable = make(chan struct{}) + bex.metrics.blobsInProgress.Inc() bex.blobs[blobDigest] = &blob{ time.Now(), &blobBroadcastMeta{ @@ -1290,16 +1430,17 @@ func (bex *blobExchangeState[RI]) processBlobBroadcastRequest(req blobBroadcastR }, nil, + chunkDigestsRoot, chunkDigests, chunkHaves, payloadLength, expirySeqNr, submitter, } - - bex.offerRequesterGadget.PleaseRecheckPendingItems() } + bex.offerRequesterGadget.PleaseRecheckPendingItems() + chDone := bex.ctx.Done() bex.subs.Go(func() { @@ -1347,6 +1488,8 @@ func (bex *blobExchangeState[RI]) getCert(blobDigest BlobDigest) (LightCertified return LightCertifiedBlob{}, fmt.Errorf("blob still in grace period, unexpected") case blobBroadcastPhaseRejected: return LightCertifiedBlob{}, fmt.Errorf("blob broadcast rejected by quorum") + case blobBroadcastPhaseExpired: + return LightCertifiedBlob{}, fmt.Errorf("blob broadcast expired") case blobBroadcastPhaseAccepted: if blob.broadcast.certOrNil == nil { return LightCertifiedBlob{}, fmt.Errorf("blob was accepted but cert is nil, unexpected") @@ -1371,31 +1514,38 @@ func (bex *blobExchangeState[RI]) eventBlobBroadcastRequestDone(ev EventBlobBroa broadcast.weServiced() } if blob.prunable() { + bex.metrics.blobsInProgress.Dec() delete(bex.blobs, ev.BlobDigest) } } -func (bex *blobExchangeState[RI]) writeBlob(blobDigest BlobDigest, payloadLength uint64, payload []byte, expirySeqNr uint64) error { +func (bex *blobExchangeState[RI]) writeBlobBeforeBroadcast(blobDigest BlobDigest, payloadLength uint64, payload []byte, expirySeqNr uint64) error { + cfgBlobChunkSize := bex.config.GetBlobChunkBytes() tx, err := bex.kv.NewUnserializedReadWriteTransactionUnchecked() if err != nil { return fmt.Errorf("failed to create read/write transaction: %w", err) } defer tx.Discard() - for i, chunkIdx := 0, uint64(0); i < len(payload); i, chunkIdx = i+BlobChunkSize, chunkIdx+1 { - payloadChunk := payload[i:min(i+BlobChunkSize, len(payload))] + + numChunks := numChunks(payloadLength, cfgBlobChunkSize) + + chunkHaves := make([]bool, numChunks) + chunkDigests := make([]BlobChunkDigest, numChunks) + for i, chunkIdx := 0, uint64(0); i < len(payload); i, chunkIdx = i+cfgBlobChunkSize, chunkIdx+1 { + payloadChunk := payload[i:min(i+cfgBlobChunkSize, len(payload))] if err := tx.WriteBlobChunk(blobDigest, chunkIdx, payloadChunk); err != nil { return fmt.Errorf("failed to write local blob chunk: %w", err) } + chunkDigests[chunkIdx] = blobtypes.MakeBlobChunkDigest(payloadChunk) + chunkHaves[chunkIdx] = true // mark all chunks as present since we're writing the full blob } - chunksHave := make([]bool, numChunks(payloadLength)) - for i := range chunksHave { - chunksHave[i] = true // mark all chunks as present since we're writing the full blob - } blobMeta := BlobMeta{ payloadLength, - chunksHave, + chunkHaves, + chunkDigests, expirySeqNr, + bex.id, } if err := tx.WriteBlobMeta(blobDigest, blobMeta); err != nil { return fmt.Errorf("failed to write local blob meta: %w", err) @@ -1403,6 +1553,7 @@ func (bex *blobExchangeState[RI]) writeBlob(blobDigest BlobDigest, payloadLength if err := tx.WriteStaleBlobIndex(staleBlob(expirySeqNr, blobDigest)); err != nil { return fmt.Errorf("failed to write stale blob index: %w", err) } + if err := tx.Commit(); err != nil { return fmt.Errorf("failed to commit kv transaction: %w", err) } @@ -1421,7 +1572,7 @@ func (bex *blobExchangeState[RI]) processBlobFetchRequest(req blobFetchRequest) blobDigest := blobtypes.MakeBlobDigest( bex.config.ConfigDigest, - cert.ChunkDigests, + cert.ChunkDigestsRoot, cert.PayloadLength, cert.ExpirySeqNr, cert.Submitter, @@ -1459,14 +1610,15 @@ func (bex *blobExchangeState[RI]) processBlobFetchRequest(req blobFetchRequest) chNotifyPayloadAvailable = existingBlob.fetch.chNotify } - - if !existingBlob.haveAllChunks() { - bex.chunkRequesterGadget.PleaseRecheckPendingItems() - } } else { chNotifyPayloadAvailable = make(chan struct{}) - chunkHaves, err := bex.loadChunkHaves(blobDigest, cert.PayloadLength) + if err := bex.createOrUpdateBlobMetaAndQuotaStats(blobDigest, cert.PayloadLength, cert.ExpirySeqNr, cert.Submitter); err != nil { + req.respond(bex.ctx, blobFetchResponse{nil, fmt.Errorf("failed to create or update blob meta and quota stats: %w", err)}) + return + } + + chunkDigests, chunkHaves, err := bex.loadChunkDigestsAndHaves(blobDigest, cert.PayloadLength) if err != nil { req.respond(bex.ctx, blobFetchResponse{nil, fmt.Errorf("failed to import blob chunk haves from disk: %w", err)}) return @@ -1483,22 +1635,24 @@ func (bex *blobExchangeState[RI]) processBlobFetchRequest(req blobFetchRequest) false, }, - cert.ChunkDigests, + cert.ChunkDigestsRoot, + chunkDigests, chunkHaves, cert.PayloadLength, cert.ExpirySeqNr, cert.Submitter, } + bex.metrics.blobsInProgress.Inc() bex.blobs[blobDigest] = newBlob if newBlob.haveAllChunks() { close(chNotifyPayloadAvailable) - } else { - bex.chunkRequesterGadget.PleaseRecheckPendingItems() } } + bex.chunkRequesterGadget.PleaseRecheckPendingItems() + bex.subs.Go(func() { select { case <-req.chDone: @@ -1529,6 +1683,69 @@ func (bex *blobExchangeState[RI]) processBlobFetchRequest(req blobFetchRequest) }) } +func (bex *blobExchangeState[RI]) createOrUpdateBlobMetaAndQuotaStats( + blobDigest BlobDigest, + payloadLength uint64, + expirySeqNr uint64, + submitter commontypes.OracleID, +) error { + tx, err := bex.kv.NewUnserializedReadWriteTransactionUnchecked() + if err != nil { + return fmt.Errorf("failed to create read/write transaction: %w", err) + } + defer tx.Discard() + + existingMeta, err := tx.ReadBlobMeta(blobDigest) + if err != nil { + return fmt.Errorf("failed to read blob meta: %w", err) + } + + if existingMeta != nil { + return nil // meta already exists, which means the quota stats already include this blob + } + + // we must bump the quota stats + existingQuotaStats, err := tx.ReadBlobQuotaStats(BlobQuotaStatsTypeAppended, submitter) + if err != nil { + return fmt.Errorf("failed to read blob quota stats: %w", err) + } + + updatedQuotaStats, ok := existingQuotaStats.Add(BlobQuotaStats{ + 1, + payloadLength, + }) + if !ok { + return fmt.Errorf("quotaStats overflow") + } + + err = tx.WriteBlobQuotaStats(BlobQuotaStatsTypeAppended, submitter, updatedQuotaStats) + if err != nil { + return fmt.Errorf("failed to write blob quota stats: %w", err) + } + + cfgBlobChunkSize := bex.config.GetBlobChunkBytes() + + // and now write the meta + blobMeta := BlobMeta{ + payloadLength, + make([]bool, numChunks(payloadLength, cfgBlobChunkSize)), + make([]BlobChunkDigest, numChunks(payloadLength, cfgBlobChunkSize)), + expirySeqNr, + submitter, + } + err = tx.WriteBlobMeta(blobDigest, blobMeta) + if err != nil { + return fmt.Errorf("failed to write blob meta: %w", err) + } + + err = tx.Commit() + if err != nil { + return fmt.Errorf("failed to commit transaction: %w", err) + } + + return nil +} + func (bex *blobExchangeState[RI]) eventBlobFetchRequestRespond(ev EventBlobFetchRequestRespond[RI]) { var ( payload []byte @@ -1556,38 +1773,43 @@ func (bex *blobExchangeState[RI]) eventBlobFetchRequestDone(ev EventBlobFetchReq fetch.weServiced() } if blob.prunable() { + bex.metrics.blobsInProgress.Dec() delete(bex.blobs, ev.BlobDigest) } } -func (bex *blobExchangeState[RI]) loadChunkHaves(blobDigest BlobDigest, payloadLength uint64) ([]bool, error) { +func (bex *blobExchangeState[RI]) loadChunkDigestsAndHaves(blobDigest BlobDigest, payloadLength uint64) ([]BlobChunkDigest, []bool, error) { tx, err := bex.kv.NewReadTransactionUnchecked() if err != nil { - return nil, fmt.Errorf("failed to create read transaction") + return nil, nil, fmt.Errorf("failed to create read transaction") } defer tx.Discard() blobMeta, err := tx.ReadBlobMeta(blobDigest) if err != nil { - return nil, fmt.Errorf("failed to read blob meta: %w", err) + return nil, nil, fmt.Errorf("failed to read blob meta: %w", err) } if blobMeta == nil { - return make([]bool, numChunks(payloadLength)), nil + numChunks := numChunks(payloadLength, bex.config.GetBlobChunkBytes()) + return make([]BlobChunkDigest, numChunks), make([]bool, numChunks), nil } if blobMeta.PayloadLength != payloadLength { - return nil, fmt.Errorf("payload length mismatch: disk %d != mem %d", blobMeta.PayloadLength, payloadLength) + return nil, nil, fmt.Errorf("payload length mismatch: disk %d != mem %d", blobMeta.PayloadLength, payloadLength) } - return blobMeta.ChunksHave, nil + return blobMeta.ChunkDigests, blobMeta.ChunkHaves, nil } -func (bex *blobExchangeState[RI]) minCertSigners() int { +func (bex *blobExchangeState[RI]) minRejectors() int { return bex.config.F + 1 } -func (bex *blobExchangeState[RI]) maxCertSigners() int { - +func (bex *blobExchangeState[RI]) minCertSigners() int { return byzquorum.Size(bex.config.N(), bex.config.F) } +func (bex *blobExchangeState[RI]) maxCertSigners() int { + return bex.config.N() +} + func (bex *blobExchangeState[RI]) verifyCert(cert *LightCertifiedBlob) error { return cert.Verify(bex.config.ConfigDigest, bex.config.OracleIdentities, bex.minCertSigners(), bex.maxCertSigners()) } diff --git a/offchainreporting2plus/internal/ocr3_1/protocol/blob_reap.go b/offchainreporting2plus/internal/ocr3_1/protocol/blob_reap.go index ff0631f8..2f3e7e04 100644 --- a/offchainreporting2plus/internal/ocr3_1/protocol/blob_reap.go +++ b/offchainreporting2plus/internal/ocr3_1/protocol/blob_reap.go @@ -71,7 +71,7 @@ func reapSingleBlob(tx KeyValueDatabaseReadWriteTransaction, staleBlob StaleBlob return fmt.Errorf("blob meta is nil") } - for chunkIndex, chunkHave := range meta.ChunksHave { + for chunkIndex, chunkHave := range meta.ChunkHaves { if !chunkHave { continue } @@ -88,6 +88,24 @@ func reapSingleBlob(tx KeyValueDatabaseReadWriteTransaction, staleBlob StaleBlob return fmt.Errorf("failed to delete stale blob index: %w", err) } + // increase reaped quota stats + + existingQuotaStats, err := tx.ReadBlobQuotaStats(BlobQuotaStatsTypeReaped, meta.Submitter) + if err != nil { + return fmt.Errorf("failed to read blob quota stats: %w", err) + } + updatedQuotaStats, ok := existingQuotaStats.Add(BlobQuotaStats{ + 1, + meta.PayloadLength, + }) + if !ok { + return fmt.Errorf("quotaStats overflow") + } + err = tx.WriteBlobQuotaStats(BlobQuotaStatsTypeReaped, meta.Submitter, updatedQuotaStats) + if err != nil { + return fmt.Errorf("failed to write blob quota stats: %w", err) + } + return nil } diff --git a/offchainreporting2plus/internal/ocr3_1/protocol/event.go b/offchainreporting2plus/internal/ocr3_1/protocol/event.go index 9ea05f03..71e828ac 100644 --- a/offchainreporting2plus/internal/ocr3_1/protocol/event.go +++ b/offchainreporting2plus/internal/ocr3_1/protocol/event.go @@ -128,24 +128,25 @@ type EventToTransmission[RI any] interface { processTransmission(t *transmissionState[RI]) } -type EventMissingOutcome[RI any] struct { - SeqNr uint64 +type EventNewCertifiedCommit[RI any] struct { + SeqNr uint64 + ReportsPlusPrecursorDigest ReportsPlusPrecursorDigest } -var _ EventToReportAttestation[struct{}] = EventMissingOutcome[struct{}]{} // implements EventToReportAttestation +var _ EventToReportAttestation[struct{}] = EventNewCertifiedCommit[struct{}]{} // implements EventToReportAttestation -func (ev EventMissingOutcome[RI]) processReportAttestation(repatt *reportAttestationState[RI]) { - repatt.eventMissingOutcome(ev) +func (ev EventNewCertifiedCommit[RI]) processReportAttestation(repatt *reportAttestationState[RI]) { + repatt.eventNewCertifiedCommit(ev) } -type EventCertifiedCommit[RI any] struct { - CertifiedCommittedReports CertifiedCommittedReports[RI] +type EventMissingReportsPlusPrecursor[RI any] struct { + SeqNr uint64 } -var _ EventToReportAttestation[struct{}] = EventCertifiedCommit[struct{}]{} // implements EventToReportAttestation +var _ EventToReportAttestation[struct{}] = EventMissingReportsPlusPrecursor[struct{}]{} // implements EventToReportAttestation -func (ev EventCertifiedCommit[RI]) processReportAttestation(repatt *reportAttestationState[RI]) { - repatt.eventCertifiedCommit(ev) +func (ev EventMissingReportsPlusPrecursor[RI]) processReportAttestation(repatt *reportAttestationState[RI]) { + repatt.eventMissingReportsPlusPrecursor(ev) } type EventComputedReports[RI any] struct { diff --git a/offchainreporting2plus/internal/ocr3_1/protocol/kvdb.go b/offchainreporting2plus/internal/ocr3_1/protocol/kvdb.go index 6437cb1c..b8f1fc2f 100644 --- a/offchainreporting2plus/internal/ocr3_1/protocol/kvdb.go +++ b/offchainreporting2plus/internal/ocr3_1/protocol/kvdb.go @@ -1,6 +1,7 @@ package protocol import ( + "github.com/smartcontractkit/libocr/commontypes" "github.com/smartcontractkit/libocr/internal/jmt" "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3_1types" "github.com/smartcontractkit/libocr/offchainreporting2plus/types" @@ -23,6 +24,9 @@ type KeyValueDatabaseSemanticRead interface { ReadAttestedStateTransitionBlock(seqNr uint64) (AttestedStateTransitionBlock, error) ReadAttestedStateTransitionBlocks(minSeqNr uint64, maxItems int) (blocks []AttestedStateTransitionBlock, more bool, err error) + ExistsUnattestedStateTransitionBlock(seqNr uint64, stateTransitionInputsDigest StateTransitionInputsDigest) (bool, error) + ReadUnattestedStateTransitionBlock(seqNr uint64, stateTransitionInputsDigest StateTransitionInputsDigest) (*StateTransitionBlock, error) + ReadTreeSyncStatus() (TreeSyncStatus, error) // ReadTreeSyncChunk retrieves a chunk of undigested key-value pairs in the // range [startIndex, requestEndInclIndex] of the key digest space. It @@ -48,9 +52,12 @@ type KeyValueDatabaseSemanticRead interface { // If only some chunks are present, it returns an error. ReadBlobPayload(BlobDigest) ([]byte, error) ReadBlobMeta(BlobDigest) (*BlobMeta, error) + ReadBlobQuotaStats(blobQuotaStatsType BlobQuotaStatsType, submitter commontypes.OracleID) (BlobQuotaStats, error) ReadBlobChunk(BlobDigest, uint64) ([]byte, error) ReadStaleBlobIndex(maxStaleSinceSeqNr uint64, limit int) ([]StaleBlob, error) + ReadReportsPlusPrecursor(seqNr uint64, reportsPlusPrecursorDigest ReportsPlusPrecursorDigest) (*ocr3_1types.ReportsPlusPrecursor, error) + jmt.RootReader jmt.NodeReader } @@ -97,6 +104,9 @@ type KeyValueDatabaseSemanticWrite interface { WriteAttestedStateTransitionBlock(seqNr uint64, block AttestedStateTransitionBlock) error DeleteAttestedStateTransitionBlocks(maxSeqNrToDelete uint64, maxItems int) (done bool, err error) + WriteUnattestedStateTransitionBlock(seqNr uint64, stateTransitionInputsDigest StateTransitionInputsDigest, stb StateTransitionBlock) error + DeleteUnattestedStateTransitionBlocks(maxSeqNrToDelete uint64, maxItems int) (done bool, err error) + // WriteHighestCommittedSeqNr writes the given sequence number to the magic // key. It is called before Commit on checked transactions. WriteHighestCommittedSeqNr(seqNr uint64) error @@ -117,11 +127,15 @@ type KeyValueDatabaseSemanticWrite interface { WriteTreeSyncStatus(state TreeSyncStatus) error WriteBlobMeta(BlobDigest, BlobMeta) error DeleteBlobMeta(BlobDigest) error + WriteBlobQuotaStats(blobQuotaStatsType BlobQuotaStatsType, submitter commontypes.OracleID, blobQuotaStats BlobQuotaStats) error WriteBlobChunk(BlobDigest, uint64, []byte) error DeleteBlobChunk(BlobDigest, uint64) error WriteStaleBlobIndex(StaleBlob) error DeleteStaleBlobIndex(StaleBlob) error + WriteReportsPlusPrecursor(seqNr uint64, reportsPlusPrecursorDigest ReportsPlusPrecursorDigest, reportsPlusPrecursor ocr3_1types.ReportsPlusPrecursor) error + DeleteReportsPlusPrecursors(minSeqNrToKeep uint64, maxItems int) (done bool, err error) + jmt.RootWriter DeleteRoots(minVersionToKeep jmt.Version, maxItems int) (done bool, err error) @@ -134,8 +148,52 @@ type KeyValueDatabaseSemanticWrite interface { type BlobMeta struct { PayloadLength uint64 - ChunksHave []bool + ChunkHaves []bool + ChunkDigests []BlobChunkDigest ExpirySeqNr uint64 + Submitter commontypes.OracleID +} + +type BlobQuotaStatsType string + +const ( + BlobQuotaStatsTypeReaped BlobQuotaStatsType = "reaped" + BlobQuotaStatsTypeAppended BlobQuotaStatsType = "appended" +) + +type BlobQuotaStats struct { + Count uint64 + CumulativePayloadLength uint64 +} + +func (b BlobQuotaStats) Add(other BlobQuotaStats) (BlobQuotaStats, bool) { + sumCount := b.Count + other.Count + if sumCount < b.Count { + return BlobQuotaStats{}, false + } + sumCumulativePayloadLength := b.CumulativePayloadLength + other.CumulativePayloadLength + if sumCumulativePayloadLength < b.CumulativePayloadLength { + return BlobQuotaStats{}, false + } + return BlobQuotaStats{ + sumCount, + sumCumulativePayloadLength, + }, true +} + +func (b BlobQuotaStats) Sub(other BlobQuotaStats) (BlobQuotaStats, bool) { + diffCount := b.Count - other.Count + if diffCount > b.Count { + return BlobQuotaStats{}, false + } + diffCumulativePayloadLength := b.CumulativePayloadLength - other.CumulativePayloadLength + if diffCumulativePayloadLength > b.CumulativePayloadLength { + return BlobQuotaStats{}, false + } + return BlobQuotaStats{ + diffCount, + diffCumulativePayloadLength, + }, true } type StaleBlob struct { diff --git a/offchainreporting2plus/internal/ocr3_1/protocol/message.go b/offchainreporting2plus/internal/ocr3_1/protocol/message.go index ff8f41b9..cce273f8 100644 --- a/offchainreporting2plus/internal/ocr3_1/protocol/message.go +++ b/offchainreporting2plus/internal/ocr3_1/protocol/message.go @@ -2,11 +2,12 @@ package protocol import ( "crypto/ed25519" - "time" "github.com/smartcontractkit/libocr/commontypes" "github.com/smartcontractkit/libocr/internal/byzquorum" "github.com/smartcontractkit/libocr/internal/jmt" + "github.com/smartcontractkit/libocr/internal/mt" + "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config" "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3_1types" "github.com/smartcontractkit/libocr/offchainreporting2plus/types" ) @@ -18,7 +19,7 @@ import ( type Message[RI any] interface { // CheckSize checks whether the given message conforms to the limits imposed by // reportingPluginLimits - CheckSize(n int, f int, limits ocr3_1types.ReportingPluginLimits, maxReportSigLen int) bool + CheckSize(n int, f int, limits ocr3_1types.ReportingPluginLimits, maxReportSigLen int, config ocr3_1config.PublicConfig) bool // process passes this Message instance to the oracle o, as a message from // oracle with the given sender index @@ -94,7 +95,7 @@ type MessageNewEpochWish[RI any] struct { var _ MessageToPacemaker[struct{}] = (*MessageNewEpochWish[struct{}])(nil) -func (msg MessageNewEpochWish[RI]) CheckSize(n int, f int, _ ocr3_1types.ReportingPluginLimits, _ int) bool { +func (msg MessageNewEpochWish[RI]) CheckSize(n int, f int, _ ocr3_1types.ReportingPluginLimits, _ int, _ ocr3_1config.PublicConfig) bool { return true } @@ -114,7 +115,7 @@ type MessageEpochStartRequest[RI any] struct { var _ MessageToOutcomeGeneration[struct{}] = (*MessageEpochStartRequest[struct{}])(nil) -func (msg MessageEpochStartRequest[RI]) CheckSize(n int, f int, limits ocr3_1types.ReportingPluginLimits, maxReportSigLen int) bool { +func (msg MessageEpochStartRequest[RI]) CheckSize(n int, f int, limits ocr3_1types.ReportingPluginLimits, maxReportSigLen int, _ ocr3_1config.PublicConfig) bool { if !msg.HighestCertified.CheckSize(n, f, limits, maxReportSigLen) { return false } @@ -142,11 +143,12 @@ func (msg MessageEpochStartRequest[RI]) epoch() uint64 { type MessageEpochStart[RI any] struct { Epoch uint64 EpochStartProof EpochStartProof + Abdicate bool } var _ MessageToOutcomeGeneration[struct{}] = (*MessageEpochStart[struct{}])(nil) -func (msg MessageEpochStart[RI]) CheckSize(n int, f int, limits ocr3_1types.ReportingPluginLimits, maxReportSigLen int) bool { +func (msg MessageEpochStart[RI]) CheckSize(n int, f int, limits ocr3_1types.ReportingPluginLimits, maxReportSigLen int, _ ocr3_1config.PublicConfig) bool { if !msg.EpochStartProof.HighestCertified.CheckSize(n, f, limits, maxReportSigLen) { return false } @@ -184,8 +186,8 @@ type MessageRoundStart[RI any] struct { var _ MessageToOutcomeGeneration[struct{}] = (*MessageRoundStart[struct{}])(nil) -func (msg MessageRoundStart[RI]) CheckSize(n int, f int, limits ocr3_1types.ReportingPluginLimits, maxReportSigLen int) bool { - return len(msg.Query) <= limits.MaxQueryLength +func (msg MessageRoundStart[RI]) CheckSize(n int, f int, limits ocr3_1types.ReportingPluginLimits, maxReportSigLen int, _ ocr3_1config.PublicConfig) bool { + return len(msg.Query) <= limits.MaxQueryBytes } func (msg MessageRoundStart[RI]) process(o *oracleState[RI], sender commontypes.OracleID) { @@ -211,8 +213,8 @@ type MessageObservation[RI any] struct { var _ MessageToOutcomeGeneration[struct{}] = (*MessageObservation[struct{}])(nil) -func (msg MessageObservation[RI]) CheckSize(n int, f int, limits ocr3_1types.ReportingPluginLimits, maxReportSigLen int) bool { - return len(msg.SignedObservation.Observation) <= limits.MaxObservationLength && len(msg.SignedObservation.Signature) == ed25519.SignatureSize +func (msg MessageObservation[RI]) CheckSize(n int, f int, limits ocr3_1types.ReportingPluginLimits, maxReportSigLen int, _ ocr3_1config.PublicConfig) bool { + return len(msg.SignedObservation.Observation) <= limits.MaxObservationBytes && len(msg.SignedObservation.Signature) == ed25519.SignatureSize } func (msg MessageObservation[RI]) process(o *oracleState[RI], sender commontypes.OracleID) { @@ -238,12 +240,12 @@ type MessageProposal[RI any] struct { var _ MessageToOutcomeGeneration[struct{}] = MessageProposal[struct{}]{} -func (msg MessageProposal[RI]) CheckSize(n int, f int, limits ocr3_1types.ReportingPluginLimits, maxReportSigLen int) bool { +func (msg MessageProposal[RI]) CheckSize(n int, f int, limits ocr3_1types.ReportingPluginLimits, maxReportSigLen int, _ ocr3_1config.PublicConfig) bool { if len(msg.AttributedSignedObservations) > n { return false } for _, aso := range msg.AttributedSignedObservations { - if len(aso.SignedObservation.Observation) > limits.MaxObservationLength { + if len(aso.SignedObservation.Observation) > limits.MaxObservationBytes { return false } if len(aso.SignedObservation.Signature) != ed25519.SignatureSize { @@ -276,7 +278,7 @@ type MessagePrepare[RI any] struct { var _ MessageToOutcomeGeneration[struct{}] = MessagePrepare[struct{}]{} -func (msg MessagePrepare[RI]) CheckSize(n int, f int, limits ocr3_1types.ReportingPluginLimits, maxReportSigLen int) bool { +func (msg MessagePrepare[RI]) CheckSize(n int, f int, limits ocr3_1types.ReportingPluginLimits, maxReportSigLen int, _ ocr3_1config.PublicConfig) bool { return len(msg.Signature) == ed25519.SignatureSize } @@ -303,7 +305,7 @@ type MessageCommit[RI any] struct { var _ MessageToOutcomeGeneration[struct{}] = MessageCommit[struct{}]{} -func (msg MessageCommit[RI]) CheckSize(n int, f int, limits ocr3_1types.ReportingPluginLimits, maxReportSigLen int) bool { +func (msg MessageCommit[RI]) CheckSize(n int, f int, limits ocr3_1types.ReportingPluginLimits, maxReportSigLen int, _ ocr3_1config.PublicConfig) bool { return len(msg.Signature) == ed25519.SignatureSize } @@ -323,13 +325,14 @@ func (msg MessageCommit[RI]) epoch() uint64 { } type MessageReportSignatures[RI any] struct { - SeqNr uint64 - ReportSignatures [][]byte + SeqNr uint64 + ReportSignatures [][]byte + ReportsPlusPrecursorDigest ReportsPlusPrecursorDigest } var _ MessageToReportAttestation[struct{}] = MessageReportSignatures[struct{}]{} -func (msg MessageReportSignatures[RI]) CheckSize(n int, f int, limits ocr3_1types.ReportingPluginLimits, maxReportSigLen int) bool { +func (msg MessageReportSignatures[RI]) CheckSize(n int, f int, limits ocr3_1types.ReportingPluginLimits, maxReportSigLen int, _ ocr3_1config.PublicConfig) bool { if len(msg.ReportSignatures) > limits.MaxReportCount { return false } @@ -350,51 +353,56 @@ func (msg MessageReportSignatures[RI]) processReportAttestation(repatt *reportAt repatt.messageReportSignatures(msg, sender) } -type MessageCertifiedCommitRequest[RI any] struct { +type MessageReportsPlusPrecursorRequest[RI any] struct { SeqNr uint64 } -var _ MessageToReportAttestation[struct{}] = MessageCertifiedCommitRequest[struct{}]{} +var _ MessageToReportAttestation[struct{}] = MessageReportsPlusPrecursorRequest[struct{}]{} -func (msg MessageCertifiedCommitRequest[RI]) CheckSize(n int, f int, _ ocr3_1types.ReportingPluginLimits, maxReportSigLen int) bool { +func (msg MessageReportsPlusPrecursorRequest[RI]) CheckSize(n int, f int, _ ocr3_1types.ReportingPluginLimits, maxReportSigLen int, _ ocr3_1config.PublicConfig) bool { return true } -func (msg MessageCertifiedCommitRequest[RI]) process(o *oracleState[RI], sender commontypes.OracleID) { +func (msg MessageReportsPlusPrecursorRequest[RI]) process(o *oracleState[RI], sender commontypes.OracleID) { o.chNetToReportAttestation <- MessageToReportAttestationWithSender[RI]{msg, sender} } -func (msg MessageCertifiedCommitRequest[RI]) processReportAttestation(repatt *reportAttestationState[RI], sender commontypes.OracleID) { - repatt.messageCertifiedCommitRequest(msg, sender) +func (msg MessageReportsPlusPrecursorRequest[RI]) processReportAttestation(repatt *reportAttestationState[RI], sender commontypes.OracleID) { + repatt.messageReportsPlusPrecursorRequest(msg, sender) } -type MessageCertifiedCommit[RI any] struct { - CertifiedCommittedReports CertifiedCommittedReports[RI] +type MessageReportsPlusPrecursor[RI any] struct { + SeqNr uint64 + ReportsPlusPrecursor ocr3_1types.ReportsPlusPrecursor } -var _ MessageToReportAttestation[struct{}] = MessageCertifiedCommit[struct{}]{} +var _ MessageToReportAttestation[struct{}] = MessageReportsPlusPrecursor[struct{}]{} -func (msg MessageCertifiedCommit[RI]) CheckSize(n int, f int, limits ocr3_1types.ReportingPluginLimits, maxReportSigLen int) bool { - return msg.CertifiedCommittedReports.CheckSize(n, f, limits, maxReportSigLen) +func (msg MessageReportsPlusPrecursor[RI]) CheckSize(n int, f int, limits ocr3_1types.ReportingPluginLimits, maxReportSigLen int, _ ocr3_1config.PublicConfig) bool { + if len(msg.ReportsPlusPrecursor) > limits.MaxReportsPlusPrecursorBytes { + return false + } + return true } -func (msg MessageCertifiedCommit[RI]) process(o *oracleState[RI], sender commontypes.OracleID) { +func (msg MessageReportsPlusPrecursor[RI]) process(o *oracleState[RI], sender commontypes.OracleID) { o.chNetToReportAttestation <- MessageToReportAttestationWithSender[RI]{msg, sender} } -func (msg MessageCertifiedCommit[RI]) processReportAttestation(repatt *reportAttestationState[RI], sender commontypes.OracleID) { - repatt.messageCertifiedCommit(msg, sender) +func (msg MessageReportsPlusPrecursor[RI]) processReportAttestation(repatt *reportAttestationState[RI], sender commontypes.OracleID) { + repatt.messageReportsPlusPrecursor(msg, sender) } type MessageBlockSyncRequest[RI any] struct { RequestHandle types.RequestHandle // actual handle for outbound message, sentinel for inbound - StartSeqNr uint64 // a successful response must contain at least the block with this sequence number - EndExclSeqNr uint64 // the response may only contain sequence numbers less than this + RequestInfo *types.RequestInfo + StartSeqNr uint64 // a successful response must contain at least the block with this sequence number + EndExclSeqNr uint64 // the response may only contain sequence numbers less than this } var _ MessageToStateSync[struct{}] = MessageBlockSyncRequest[struct{}]{} -func (msg MessageBlockSyncRequest[RI]) CheckSize(n int, f int, _ ocr3_1types.ReportingPluginLimits, _ int) bool { +func (msg MessageBlockSyncRequest[RI]) CheckSize(n int, f int, _ ocr3_1types.ReportingPluginLimits, _ int, _ ocr3_1config.PublicConfig) bool { return true } @@ -413,7 +421,7 @@ type MessageStateSyncSummary[RI any] struct { var _ MessageToStateSync[struct{}] = MessageStateSyncSummary[struct{}]{} -func (msg MessageStateSyncSummary[RI]) CheckSize(n int, f int, _ ocr3_1types.ReportingPluginLimits, _ int) bool { +func (msg MessageStateSyncSummary[RI]) CheckSize(n int, f int, _ ocr3_1types.ReportingPluginLimits, _ int, _ ocr3_1config.PublicConfig) bool { return true } @@ -434,8 +442,8 @@ type MessageBlockSyncResponse[RI any] struct { var _ MessageToStateSync[struct{}] = MessageBlockSyncResponse[struct{}]{} -func (msg MessageBlockSyncResponse[RI]) CheckSize(n int, f int, limits ocr3_1types.ReportingPluginLimits, maxReportSigLen int) bool { - if len(msg.AttestedStateTransitionBlocks) > MaxBlocksPerBlockSyncResponse { +func (msg MessageBlockSyncResponse[RI]) CheckSize(n int, f int, limits ocr3_1types.ReportingPluginLimits, maxReportSigLen int, config ocr3_1config.PublicConfig) bool { + if len(msg.AttestedStateTransitionBlocks) > config.GetMaxBlocksPerBlockSyncResponse() { return false } for _, astb := range msg.AttestedStateTransitionBlocks { @@ -456,6 +464,7 @@ func (msg MessageBlockSyncResponse[RI]) processStateSync(stasy *stateSyncState[R type MessageTreeSyncChunkRequest[RI any] struct { RequestHandle types.RequestHandle // actual handle for outbound message, sentinel for inbound + RequestInfo *types.RequestInfo ToSeqNr uint64 StartIndex jmt.Digest EndInclIndex jmt.Digest @@ -463,7 +472,7 @@ type MessageTreeSyncChunkRequest[RI any] struct { var _ MessageToStateSync[struct{}] = MessageTreeSyncChunkRequest[struct{}]{} -func (msg MessageTreeSyncChunkRequest[RI]) CheckSize(n int, f int, limits ocr3_1types.ReportingPluginLimits, maxReportSigLen int) bool { +func (msg MessageTreeSyncChunkRequest[RI]) CheckSize(n int, f int, limits ocr3_1types.ReportingPluginLimits, maxReportSigLen int, _ ocr3_1config.PublicConfig) bool { return true } @@ -488,7 +497,7 @@ type MessageTreeSyncChunkResponse[RI any] struct { var _ MessageToStateSync[struct{}] = MessageTreeSyncChunkResponse[struct{}]{} -func (msg MessageTreeSyncChunkResponse[RI]) CheckSize(n int, f int, limits ocr3_1types.ReportingPluginLimits, maxReportSigLen int) bool { +func (msg MessageTreeSyncChunkResponse[RI]) CheckSize(n int, f int, limits ocr3_1types.ReportingPluginLimits, maxReportSigLen int, config ocr3_1config.PublicConfig) bool { if len(msg.BoundingLeaves) > jmt.MaxBoundingLeaves { return false } @@ -497,20 +506,20 @@ func (msg MessageTreeSyncChunkResponse[RI]) CheckSize(n int, f int, limits ocr3_ return false } } - if len(msg.KeyValues) > MaxTreeSyncChunkKeys { + if len(msg.KeyValues) > config.GetMaxTreeSyncChunkKeys() { return false } treeSyncChunkLeavesSize := 0 for _, kv := range msg.KeyValues { - if len(kv.Key) > ocr3_1types.MaxMaxKeyValueKeyLength { + if len(kv.Key) > ocr3_1types.MaxMaxKeyValueKeyBytes { return false } - if len(kv.Value) > ocr3_1types.MaxMaxKeyValueValueLength { + if len(kv.Value) > ocr3_1types.MaxMaxKeyValueValueBytes { return false } treeSyncChunkLeavesSize += len(kv.Key) + len(kv.Value) } - if treeSyncChunkLeavesSize > MaxTreeSyncChunkKeysPlusValuesLength { + if treeSyncChunkLeavesSize > config.GetMaxTreeSyncChunkKeysPlusValuesBytes() { return false } return true @@ -524,27 +533,17 @@ func (msg MessageTreeSyncChunkResponse[RI]) processStateSync(stasy *stateSyncSta stasy.messageTreeSyncChunkResponse(msg, sender) } -type MessageBlobOfferRequestInfo struct { - ExpiryTimestamp time.Time -} - type MessageBlobOffer[RI any] struct { - RequestHandle types.RequestHandle // actual handle for outbound message, sentinel for inbound - RequestInfo *MessageBlobOfferRequestInfo - ChunkDigests []BlobChunkDigest - PayloadLength uint64 - ExpirySeqNr uint64 + RequestHandle types.RequestHandle // actual handle for outbound message, sentinel for inbound + RequestInfo *types.RequestInfo + ChunkDigestsRoot mt.Digest + PayloadLength uint64 + ExpirySeqNr uint64 } var _ MessageToBlobExchange[struct{}] = MessageBlobOffer[struct{}]{} -func (msg MessageBlobOffer[RI]) CheckSize(n int, f int, limits ocr3_1types.ReportingPluginLimits, _ int) bool { - if msg.PayloadLength > uint64(limits.MaxBlobPayloadLength) { - return false - } - if uint64(len(msg.ChunkDigests)) != numChunks(msg.PayloadLength) { - return false - } +func (msg MessageBlobOffer[RI]) CheckSize(n int, f int, limits ocr3_1types.ReportingPluginLimits, _ int, config ocr3_1config.PublicConfig) bool { return true } @@ -565,7 +564,7 @@ type MessageBlobOfferResponse[RI any] struct { var _ MessageToBlobExchange[struct{}] = MessageBlobOfferResponse[struct{}]{} -func (msg MessageBlobOfferResponse[RI]) CheckSize(n int, f int, _ ocr3_1types.ReportingPluginLimits, _ int) bool { +func (msg MessageBlobOfferResponse[RI]) CheckSize(n int, f int, _ ocr3_1types.ReportingPluginLimits, _ int, _ ocr3_1config.PublicConfig) bool { if msg.RejectOffer { return len(msg.Signature) == 0 } else { @@ -581,22 +580,16 @@ func (msg MessageBlobOfferResponse[RI]) processBlobExchange(bex *blobExchangeSta bex.messageBlobOfferResponse(msg, sender) } -type MessageBlobChunkRequestInfo struct { - ExpiryTimestamp time.Time -} - type MessageBlobChunkRequest[RI any] struct { RequestHandle types.RequestHandle // actual handle for outbound message, sentinel for inbound - - RequestInfo *MessageBlobChunkRequestInfo - - BlobDigest BlobDigest - ChunkIndex uint64 + RequestInfo *types.RequestInfo + BlobDigest BlobDigest + ChunkIndex uint64 } var _ MessageToBlobExchange[struct{}] = MessageBlobChunkRequest[struct{}]{} -func (msg MessageBlobChunkRequest[RI]) CheckSize(n int, f int, _ ocr3_1types.ReportingPluginLimits, _ int) bool { +func (msg MessageBlobChunkRequest[RI]) CheckSize(n int, f int, _ ocr3_1types.ReportingPluginLimits, _ int, _ ocr3_1config.PublicConfig) bool { return true } @@ -615,12 +608,13 @@ type MessageBlobChunkResponse[RI any] struct { ChunkIndex uint64 GoAway bool Chunk []byte + Proof []mt.Digest } var _ MessageToBlobExchange[struct{}] = MessageBlobChunkResponse[struct{}]{} -func (msg MessageBlobChunkResponse[RI]) CheckSize(n int, f int, _ ocr3_1types.ReportingPluginLimits, _ int) bool { - if len(msg.Chunk) > BlobChunkSize { +func (msg MessageBlobChunkResponse[RI]) CheckSize(n int, f int, _ ocr3_1types.ReportingPluginLimits, _ int, config ocr3_1config.PublicConfig) bool { + if len(msg.Chunk) > config.GetBlobChunkBytes() { return false } return true diff --git a/offchainreporting2plus/internal/ocr3_1/protocol/metrics.go b/offchainreporting2plus/internal/ocr3_1/protocol/metrics.go index 4e8f9785..968075c7 100644 --- a/offchainreporting2plus/internal/ocr3_1/protocol/metrics.go +++ b/offchainreporting2plus/internal/ocr3_1/protocol/metrics.go @@ -98,3 +98,27 @@ func (om *outcomeGenerationMetrics) Close() { om.registerer.Unregister(om.includedObservationsTotal) om.registerer.Unregister(om.ledCommittedRoundsTotal) } + +type blobExchangeMetrics struct { + registerer prometheus.Registerer + blobsInProgress prometheus.Gauge +} + +func newBlobExchangeMetrics(registerer prometheus.Registerer, + logger commontypes.Logger) *blobExchangeMetrics { + + blobsInProgress := prometheus.NewGauge(prometheus.GaugeOpts{ + Name: "ocr3_1_experimental_blobs_in_progress", + Help: "The number of blobs that are actively being broadcast or fetched", + }) + metricshelper.RegisterOrLogError(logger, registerer, blobsInProgress, "ocr3_1_experimental_blobs_in_progress") + + return &blobExchangeMetrics{ + registerer, + blobsInProgress, + } +} + +func (bm *blobExchangeMetrics) Close() { + bm.registerer.Unregister(bm.blobsInProgress) +} diff --git a/offchainreporting2plus/internal/ocr3_1/protocol/oracle.go b/offchainreporting2plus/internal/ocr3_1/protocol/oracle.go index 2d4123d1..f8b20d06 100644 --- a/offchainreporting2plus/internal/ocr3_1/protocol/oracle.go +++ b/offchainreporting2plus/internal/ocr3_1/protocol/oracle.go @@ -10,7 +10,7 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/smartcontractkit/libocr/commontypes" "github.com/smartcontractkit/libocr/internal/loghelper" - "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3config" + "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config" "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3_1types" "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/smartcontractkit/libocr/subprocesses" @@ -25,7 +25,7 @@ func RunOracle[RI any]( ctx context.Context, blobEndpointWrapper *BlobEndpointWrapper, - config ocr3config.SharedConfig, + config ocr3_1config.SharedConfig, contractTransmitter ocr3types.ContractTransmitter[RI], database Database, id commontypes.OracleID, @@ -66,7 +66,7 @@ type oracleState[RI any] struct { ctx context.Context blobEndpointWrapper *BlobEndpointWrapper - config ocr3config.SharedConfig + config ocr3_1config.SharedConfig contractTransmitter ocr3types.ContractTransmitter[RI] database Database id commontypes.OracleID @@ -261,6 +261,7 @@ func (o *oracleState[RI]) run() { chReportAttestationToTransmission, o.config, o.contractTransmitter, + o.kvDb, o.logger, o.netEndpoint, o.onchainKeyring, @@ -322,7 +323,7 @@ func (o *oracleState[RI]) run() { ) }) - publicConfigMetrics := ocr3config.NewPublicConfigMetrics(o.metricsRegisterer, o.logger, o.config.PublicConfig) + publicConfigMetrics := ocr3_1config.NewPublicConfigMetrics(o.metricsRegisterer, o.logger, o.config.PublicConfig) defer publicConfigMetrics.Close() chNet := o.netEndpoint.Receive() diff --git a/offchainreporting2plus/internal/ocr3_1/protocol/outcome_generation.go b/offchainreporting2plus/internal/ocr3_1/protocol/outcome_generation.go index f730118e..728e1984 100644 --- a/offchainreporting2plus/internal/ocr3_1/protocol/outcome_generation.go +++ b/offchainreporting2plus/internal/ocr3_1/protocol/outcome_generation.go @@ -2,16 +2,17 @@ package protocol import ( "context" + "fmt" "time" "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/common" + "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config" "github.com/prometheus/client_golang/prometheus" "github.com/smartcontractkit/libocr/commontypes" "github.com/smartcontractkit/libocr/internal/loghelper" "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/common/pool" - "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3config" "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3_1types" "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/smartcontractkit/libocr/subprocesses" @@ -35,7 +36,7 @@ func RunOutcomeGeneration[RI any]( chOutcomeGenerationToReportAttestation chan<- EventToReportAttestation[RI], chOutcomeGenerationToStateSync chan<- EventToStateSync[RI], blobBroadcastFetcher ocr3_1types.BlobBroadcastFetcher, - config ocr3config.SharedConfig, + config ocr3_1config.SharedConfig, database Database, id commontypes.OracleID, kvDb KeyValueDatabase, @@ -87,7 +88,7 @@ type outcomeGenerationState[RI any] struct { chOutcomeGenerationToReportAttestation chan<- EventToReportAttestation[RI] chOutcomeGenerationToStateSync chan<- EventToStateSync[RI] blobBroadcastFetcher ocr3_1types.BlobBroadcastFetcher - config ocr3config.SharedConfig + config ocr3_1config.SharedConfig database Database id commontypes.OracleID kvDb KeyValueDatabase @@ -130,6 +131,8 @@ type followerState[RI any] struct { tInitial <-chan time.Time + leaderAbdicated bool + roundStartPool *pool.Pool[MessageRoundStart[RI]] query *types.Query @@ -148,15 +151,38 @@ type followerState[RI any] struct { commitPool *pool.Pool[CommitSignature] } -type stateTransitionInfo struct { +//go-sumtype:decl stateTransitionInfo + +type stateTransitionInfo interface { + isStateTransitionInfo() + digests() stateTransitionInfoDigests +} + +type stateTransitionInfoDigests struct { InputsDigest StateTransitionInputsDigest - Outputs StateTransitionOutputs OutputDigest StateTransitionOutputDigest StateRootDigest StateRootDigest - ReportsPlusPrecursor ocr3_1types.ReportsPlusPrecursor ReportsPlusPrecursorDigest ReportsPlusPrecursorDigest } +func (stateTransitionInfoDigests) isStateTransitionInfo() {} + +func (stid stateTransitionInfoDigests) digests() stateTransitionInfoDigests { + return stid +} + +type stateTransitionInfoDigestsAndPreimages struct { + stateTransitionInfoDigests + Outputs StateTransitionOutputs + ReportsPlusPrecursor ocr3_1types.ReportsPlusPrecursor +} + +func (stateTransitionInfoDigestsAndPreimages) isStateTransitionInfo() {} + +func (stid stateTransitionInfoDigestsAndPreimages) digests() stateTransitionInfoDigests { + return stid.stateTransitionInfoDigests +} + type sharedState struct { e uint64 // Current epoch number l commontypes.OracleID // Current leader number @@ -204,10 +230,11 @@ func (outgen *outcomeGenerationState[RI]) run(restoredCert CertifiedPrepareOrCom outgen.followerState = followerState[RI]{ outgenFollowerPhaseUnknown, nil, + false, nil, nil, nil, - stateTransitionInfo{}, + stateTransitionInfoDigests{}, nil, restoredCert, nil, @@ -224,6 +251,10 @@ func (outgen *outcomeGenerationState[RI]) run(restoredCert CertifiedPrepareOrCom restoredCommitedSeqNr, } + outgen.subs.Go(func() { + RunOutcomeGenerationReap(outgen.ctx, outgen.logger, outgen.kvDb) + }) + // Event Loop chDone := outgen.ctx.Done() for { @@ -333,8 +364,9 @@ func (outgen *outcomeGenerationState[RI]) eventNewEpochStart(ev EventNewEpochSta outgen.sharedState.seqNr = 0 outgen.followerState.phase = outgenFollowerPhaseNewEpoch - outgen.followerState.tInitial = time.After(outgen.config.DeltaInitial) - outgen.followerState.stateTransitionInfo = stateTransitionInfo{} + outgen.followerState.tInitial = time.After(outgen.config.GetDeltaInitial()) + outgen.followerState.leaderAbdicated = false + outgen.followerState.stateTransitionInfo = stateTransitionInfoDigests{} outgen.followerState.roundStartPool = pool.NewPool[MessageRoundStart[RI]](poolSize) outgen.followerState.proposalPool = pool.NewPool[MessageProposal[RI]](poolSize) @@ -348,6 +380,7 @@ func (outgen *outcomeGenerationState[RI]) eventNewEpochStart(ev EventNewEpochSta outgen.leaderState.tGrace = nil outgen.refreshCommittedSeqNrAndCert() + outgen.sendStateSyncRequestFromCertifiedPrepareOrCommit(outgen.followerState.cert) var highestCertified CertifiedPrepareOrCommit var highestCertifiedTimestamp HighestCertifiedTimestamp @@ -423,3 +456,211 @@ func callPluginFromOutcomeGenerationBackground[T any]( }, ) } + +func (outgen *outcomeGenerationState[RI]) sendStateSyncRequestFromCertifiedPrepareOrCommit(cert CertifiedPrepareOrCommit) { + var seqNr uint64 + switch cert := cert.(type) { + case *CertifiedPrepare: + seqNr = cert.PrepareSeqNr - 1 + case *CertifiedCommit: + seqNr = cert.CommitSeqNr + } + + select { + case outgen.chOutcomeGenerationToStateSync <- EventStateSyncRequest[RI]{ + seqNr, + }: + case <-outgen.ctx.Done(): + } +} + +func (outgen *outcomeGenerationState[RI]) tryToMoveCertAndKVStateToCommitQC(commitQC *CertifiedCommit) { + ok := outgen.commit(*commitQC) + if !ok { + outgen.logger.Error("commit() failed", commontypes.LogFields{ + "commitQCSeqNr": commitQC.CommitSeqNr, + }) + // We intentionally fall through to give a chance to advance the KV + // state regardless of the cert persistence failure. + } + + // Early return to avoid unnecessary error logs + { + committedKVSeqNr, err := outgen.committedKVSeqNr() + if err != nil { + outgen.logger.Error("failed to read highest committed kv seq nr", commontypes.LogFields{ + "error": err, + }) + return + } + if committedKVSeqNr == commitQC.CommitSeqNr { + // already where we want to be + return + } + if committedKVSeqNr+1 != commitQC.CommitSeqNr { + outgen.logger.Debug("commit qc seq nr quite ahead from committed kv seq nr, can't do anything", commontypes.LogFields{ + "committedKVSeqNr": committedKVSeqNr, + "commitQCSeqNr": commitQC.CommitSeqNr, + }) + return + } + } + + tx, err := outgen.kvDb.NewSerializedReadWriteTransaction(commitQC.CommitSeqNr) + if err != nil { + + outgen.logger.Error("failed to create serialized transaction", commontypes.LogFields{ + "error": err, + }) + return + } + defer tx.Discard() + + committedKVSeqNr, err := tx.ReadHighestCommittedSeqNr() + if err != nil { + outgen.logger.Error("failed to read highest committed kv seq nr", commontypes.LogFields{ + "error": err, + }) + return + } + + if commitQC.CommitSeqNr == committedKVSeqNr { + outgen.logger.Debug("kv state already at commit qc seq nr, nothing to do", commontypes.LogFields{ + "committedKVSeqNr": committedKVSeqNr, + "commitQCSeqNr": commitQC.CommitSeqNr, + }) + return + } + + if commitQC.CommitSeqNr != committedKVSeqNr+1 { + outgen.logger.Debug("commit qc seq nr quite ahead from committed kv seq nr, can't do anything", commontypes.LogFields{ + "committedKVSeqNr": committedKVSeqNr, + "commitQCSeqNr": commitQC.CommitSeqNr, + }) + return + } + + stb, err := tx.ReadUnattestedStateTransitionBlock(commitQC.CommitSeqNr, commitQC.StateTransitionInputsDigest) + if err != nil { + outgen.logger.Error("error during ReadUnattestedStateTransitionBlock", commontypes.LogFields{ + "commitQCSeqNr": commitQC.CommitSeqNr, + "error": err, + }) + return + } + if stb == nil { + outgen.logger.Debug("unattested state transition block not found, can't move kv state", commontypes.LogFields{ + "commitQCSeqNr": commitQC.CommitSeqNr, + }) + return + } + if err := outgen.isCompatibleUnattestedStateTransitionBlockSanityCheck(commitQC, *stb); err != nil { + outgen.logger.Critical("sanity check of unattested state transition block failed, very surprising!", commontypes.LogFields{ + "commitQCSeqNr": commitQC.CommitSeqNr, + "error": err, + }) + return + } + + astb := AttestedStateTransitionBlock{ + *stb, + commitQC.CommitQuorumCertificate, + } + + // write astb + err = tx.WriteAttestedStateTransitionBlock(commitQC.CommitSeqNr, astb) + if err != nil { + outgen.logger.Error("error writing attested state transition block", commontypes.LogFields{ + "commitQCSeqNr": commitQC.CommitSeqNr, + "error": err, + }) + return + } + + // apply write set + stateRootDigest, err := tx.ApplyWriteSet(stb.StateTransitionOutputs.WriteSet) + if err != nil { + outgen.logger.Error("error applying write set", commontypes.LogFields{ + "commitQCSeqNr": commitQC.CommitSeqNr, + "error": err, + }) + return + } + + if stateRootDigest != stb.StateRootDigest { + outgen.logger.Error("state root digest mismatch from write set application", commontypes.LogFields{ + "commitQCSeqNr": commitQC.CommitSeqNr, + "expected": stb.StateRootDigest, + "actual": stateRootDigest, + }) + return + } + + err = tx.Commit() + if err != nil { + outgen.logger.Error("error committing transaction", commontypes.LogFields{ + "commitQCSeqNr": commitQC.CommitSeqNr, + "error": err, + }) + return + } + + outgen.logger.Debug("successfully moved kv state to commit qc", commontypes.LogFields{ + "oldCommittedKVSeqNr": committedKVSeqNr, + "newCommittedKVSeqNr": commitQC.CommitSeqNr, + }) +} + +func (outgen *outcomeGenerationState[RI]) persistUnattestedStateTransitionBlockAndReportsPlusPrecursor(stb StateTransitionBlock, stateTransitionInputsDigest StateTransitionInputsDigest, reportsPlusPrecursor ocr3_1types.ReportsPlusPrecursor) error { + kvTxn, err := outgen.kvDb.NewUnserializedReadWriteTransactionUnchecked() + if err != nil { + return err + } + defer kvTxn.Discard() + seqNr := stb.BlockSeqNr + err = kvTxn.WriteUnattestedStateTransitionBlock(seqNr, stateTransitionInputsDigest, stb) + if err != nil { + return fmt.Errorf("failed to write unattested state transition block: %w", err) + } + err = kvTxn.WriteReportsPlusPrecursor(seqNr, stb.ReportsPlusPrecursorDigest, reportsPlusPrecursor) + if err != nil { + return fmt.Errorf("failed to write reports plus precursor: %w", err) + } + err = kvTxn.Commit() + if err != nil { + return fmt.Errorf("failed to commit: %w", err) + } + return nil +} + +func (outgen *outcomeGenerationState[RI]) isCompatibleUnattestedStateTransitionBlockSanityCheck(commitQC *CertifiedCommit, stb StateTransitionBlock) error { + stbStateTransitionOutputsDigest := MakeStateTransitionOutputDigest( + outgen.config.ConfigDigest, + stb.BlockSeqNr, + stb.StateTransitionOutputs.WriteSet, + ) + + if stbStateTransitionOutputsDigest != commitQC.StateTransitionOutputsDigest { + return fmt.Errorf("local state transition block outputs digest does not match commitQC: expected %s but got %s", commitQC.StateTransitionOutputsDigest, stbStateTransitionOutputsDigest) + } + if stb.StateRootDigest != commitQC.StateRootDigest { + return fmt.Errorf("local state transition block state root digest does not match commitQC: expected %s but got %s", commitQC.StateRootDigest, stb.StateRootDigest) + } + if stb.ReportsPlusPrecursorDigest != commitQC.ReportsPlusPrecursorDigest { + return fmt.Errorf("local state transition block reportsPlusPrecursor digest does not match commitQC: expected %s but got %s", commitQC.ReportsPlusPrecursorDigest, stb.ReportsPlusPrecursorDigest) + } + return nil +} + +func (outgen *outcomeGenerationState[RI]) committedKVSeqNr() (uint64, error) { + return committedKVSeqNr(outgen.kvDb) +} + +func committedKVSeqNr(kvDb KeyValueDatabase) (uint64, error) { + tx, err := kvDb.NewReadTransactionUnchecked() + if err != nil { + return 0, fmt.Errorf("failed to create read transaction: %w", err) + } + defer tx.Discard() + return tx.ReadHighestCommittedSeqNr() +} diff --git a/offchainreporting2plus/internal/ocr3_1/protocol/outcome_generation_follower.go b/offchainreporting2plus/internal/ocr3_1/protocol/outcome_generation_follower.go index 4ec7a019..3b1d26ca 100644 --- a/offchainreporting2plus/internal/ocr3_1/protocol/outcome_generation_follower.go +++ b/offchainreporting2plus/internal/ocr3_1/protocol/outcome_generation_follower.go @@ -1,7 +1,6 @@ package protocol import ( - "bytes" "context" "sync" @@ -18,6 +17,7 @@ type outgenFollowerPhase string const ( outgenFollowerPhaseUnknown outgenFollowerPhase = "unknown" outgenFollowerPhaseNewEpoch outgenFollowerPhase = "newEpoch" + outgenFollowerPhaseEpochStartReceived outgenFollowerPhase = "epochStartReceived" outgenFollowerPhaseNewRound outgenFollowerPhase = "newRound" outgenFollowerPhaseBackgroundObservation outgenFollowerPhase = "backgroundObservation" outgenFollowerPhaseSentObservation outgenFollowerPhase = "sentObservation" @@ -30,7 +30,7 @@ const ( func (outgen *outcomeGenerationState[RI]) eventTInitialTimeout() { outgen.logger.Debug("TInitial fired", commontypes.LogFields{ "seqNr": outgen.sharedState.seqNr, - "deltaInitial": outgen.config.DeltaInitial.String(), + "deltaInitial": outgen.config.GetDeltaInitial().String(), }) select { case outgen.chOutcomeGenerationToPacemaker <- EventNewEpochRequest[RI]{}: @@ -44,6 +44,7 @@ func (outgen *outcomeGenerationState[RI]) messageEpochStart(msg MessageEpochStar "sender": sender, "msgEpoch": msg.Epoch, "msgHighestCertifiedTimestamp": msg.EpochStartProof.HighestCertified.Timestamp(), + "msgAbdicate": msg.Abdicate, }) if msg.Epoch != outgen.sharedState.e { @@ -68,6 +69,8 @@ func (outgen *outcomeGenerationState[RI]) messageEpochStart(msg MessageEpochStar return } + outgen.followerState.phase = outgenFollowerPhaseEpochStartReceived + { err := msg.EpochStartProof.Verify( outgen.ID(), @@ -83,29 +86,31 @@ func (outgen *outcomeGenerationState[RI]) messageEpochStart(msg MessageEpochStar } outgen.followerState.tInitial = nil + outgen.followerState.leaderAbdicated = msg.Abdicate - outgen.refreshCommittedSeqNrAndCert() - if !outgen.ensureHighestCertifiedIsCompatible(msg.EpochStartProof.HighestCertified, "MessageEpochStart") { - select { - case outgen.chOutcomeGenerationToStateSync <- EventStateSyncRequest[RI]{ - msg.EpochStartProof.HighestCertified.SeqNr(), - }: - case <-outgen.ctx.Done(): - } - return - } + outgen.refreshCommittedSeqNrAndCert() // call in case stasy has made progress in the meanwhile + outgen.sendStateSyncRequestFromCertifiedPrepareOrCommit(msg.EpochStartProof.HighestCertified) if msg.EpochStartProof.HighestCertified.IsGenesis() { outgen.sharedState.firstSeqNrOfEpoch = outgen.sharedState.committedSeqNr + 1 outgen.startSubsequentFollowerRound() } else if commitQC, ok := msg.EpochStartProof.HighestCertified.(*CertifiedCommit); ok { - outgen.commit(*commitQC) - + outgen.tryToMoveCertAndKVStateToCommitQC(commitQC) + if outgen.sharedState.committedSeqNr != commitQC.CommitSeqNr { + outgen.logger.Warn("cannot process MessageEpochStart, mismatching committedSeqNr, will not be able to participate in epoch", commontypes.LogFields{ + "commitSeqNr": commitQC.CommitSeqNr, + "committedSeqNr": outgen.sharedState.committedSeqNr, + }) + return + } outgen.sharedState.firstSeqNrOfEpoch = outgen.sharedState.committedSeqNr + 1 + if msg.Abdicate { + outgen.sendNewEpochRequestToPacemakerDueToLeaderAbdication() + return + } outgen.startSubsequentFollowerRound() } else { // We're dealing with a re-proposal from a failed epoch - prepareQc, ok := msg.EpochStartProof.HighestCertified.(*CertifiedPrepare) if !ok { outgen.logger.Critical("cast to CertifiedPrepare failed while processing MessageEpochStart", commontypes.LogFields{ @@ -114,117 +119,29 @@ func (outgen *outcomeGenerationState[RI]) messageEpochStart(msg MessageEpochStar return } - prepareQcSeqNr := prepareQc.SeqNr() - - outgen.sharedState.firstSeqNrOfEpoch = prepareQcSeqNr + 1 - outgen.sharedState.seqNr = prepareQcSeqNr - outgen.sharedState.observationQuorum = nil - - outgen.followerState.query = nil - outgen.ensureOpenKVTransactionDiscarded() - - if prepareQcSeqNr == outgen.sharedState.committedSeqNr { - - stateTransitionInputsDigest := prepareQc.StateTransitionInputsDigest - stateRootDigest := prepareQc.StateRootDigest - - stateTransitionOutputDigest := MakeStateTransitionOutputDigest( - outgen.ID(), - prepareQcSeqNr, - prepareQc.StateTransitionOutputs.WriteSet, - ) - - reportPlusPrecursorDigest := MakeReportsPlusPrecursorDigest( - outgen.ID(), - prepareQcSeqNr, - prepareQc.ReportsPlusPrecursor, - ) - - prepareSignature, err := MakePrepareSignature( - outgen.ID(), - prepareQcSeqNr, - stateTransitionInputsDigest, - stateTransitionOutputDigest, - stateRootDigest, - reportPlusPrecursorDigest, - outgen.offchainKeyring.OffchainSign, - ) - if err != nil { - outgen.logger.Critical("failed to sign Prepare", commontypes.LogFields{ - "seqNr": outgen.sharedState.seqNr, - "error": err, - }) - return - } - - outgen.followerState.phase = outgenFollowerPhaseSentPrepare - outgen.followerState.stateTransitionInfo = stateTransitionInfo{ - stateTransitionInputsDigest, - prepareQc.StateTransitionOutputs, - stateTransitionOutputDigest, - stateRootDigest, - prepareQc.ReportsPlusPrecursor, - reportPlusPrecursorDigest, - } - - outgen.logger.Debug("broadcasting MessagePrepare (reproposal where prepareQcSeqNr == committedSeqNr)", commontypes.LogFields{ - "seqNr": outgen.sharedState.seqNr, - }) - outgen.netSender.Broadcast(MessagePrepare[RI]{ - outgen.sharedState.e, - prepareQcSeqNr, - prepareSignature, + if prepareQc.SeqNr() < outgen.sharedState.committedSeqNr { + outgen.logger.Warn("cannot process MessageEpochStart, prepareQC seqNr is less than committedSeqNr, will not be able to participate in epoch", commontypes.LogFields{ + "prepareQCSeqNr": prepareQc.SeqNr(), + "committedSeqNr": outgen.sharedState.committedSeqNr, }) return } - outgen.followerState.phase = outgenFollowerPhaseBackgroundProposalStateTransition - outgen.followerState.stateTransitionInfo = stateTransitionInfo{} - outgen.ensureOpenKVTransactionDiscarded() + outgen.followerState.stateTransitionInfo = stateTransitionInfoDigests{ + prepareQc.StateTransitionInputsDigest, + prepareQc.StateTransitionOutputsDigest, + prepareQc.StateRootDigest, + prepareQc.ReportsPlusPrecursorDigest, + } - outgen.logger.Debug("re-executing StateTransition from MessagePrepare (reproposal where prepareQcSeqNr == committedSeqNr+1)", commontypes.LogFields{ - "seqNr": outgen.sharedState.seqNr, - }) + outgen.sharedState.firstSeqNrOfEpoch = prepareQc.SeqNr() + 1 + outgen.sharedState.seqNr = prepareQc.SeqNr() + outgen.sharedState.observationQuorum = nil - kvReadWriteTxn, err := outgen.kvDb.NewSerializedReadWriteTransaction(prepareQcSeqNr) - if err != nil { - outgen.logger.Warn("could not create kv read/write transaction", commontypes.LogFields{ - "seqNr": outgen.sharedState.seqNr, - "err": err, - }) - return - } + outgen.followerState.query = nil + outgen.ensureOpenKVTransactionDiscarded() - { - ctx := outgen.ctx - logger := outgen.logger - ogid := outgen.ID() - roundCtx := outgen.RoundCtx(prepareQcSeqNr) - - inputsDigest := prepareQc.StateTransitionInputsDigest - writeSet := prepareQc.StateTransitionOutputs.WriteSet - reportsPlusPrecursor := prepareQc.ReportsPlusPrecursor - stateRootDigest := prepareQc.StateRootDigest - - outgen.subs.Go(func() { - outgen.backgroundProposalStateTransition( - ctx, - logger, - ogid, - roundCtx, - - inputsDigest, - writeSet, - stateRootDigest, - reportsPlusPrecursor, - - types.AttributedQuery{}, - nil, - - kvReadWriteTxn, - ) - }) - } + outgen.broadcastMessagePrepare() } } @@ -234,7 +151,7 @@ func (outgen *outcomeGenerationState[RI]) startSubsequentFollowerRound() { outgen.followerState.phase = outgenFollowerPhaseNewRound outgen.followerState.query = nil - outgen.followerState.stateTransitionInfo = stateTransitionInfo{} + outgen.followerState.stateTransitionInfo = stateTransitionInfoDigests{} outgen.ensureOpenKVTransactionDiscarded() outgen.logger.Debug("starting new follower round", commontypes.LogFields{ "seqNr": outgen.sharedState.seqNr, @@ -333,6 +250,7 @@ func (outgen *outcomeGenerationState[RI]) tryProcessRoundStartPool() { outgen.sharedState.l, } kvReadTxn, err := outgen.kvDb.NewReadTransaction(roundCtx.SeqNr) + if err != nil { outgen.logger.Warn("failed to create new transaction, aborting tryProcessRoundStartPool", commontypes.LogFields{ "seqNr": roundCtx.SeqNr, @@ -357,7 +275,7 @@ func (outgen *outcomeGenerationState[RI]) backgroundObservation( ctx, logger, "Observation", - outgen.config.MaxDurationObservation, + outgen.config.WarnDurationObservation, roundCtx, func(ctx context.Context, roundCtx RoundContext) (types.Observation, error) { return outgen.reportingPlugin.Observation(ctx, @@ -513,6 +431,7 @@ func (outgen *outcomeGenerationState[RI]) tryProcessProposalPool() { "err": err, }) return + } { @@ -533,12 +452,6 @@ func (outgen *outcomeGenerationState[RI]) tryProcessProposalPool() { logger, ogid, roundCtx, - - StateTransitionInputsDigest{}, - nil, - StateRootDigest{}, - nil, - aq, asos, kvReadWriteTxn, @@ -552,12 +465,6 @@ func (outgen *outcomeGenerationState[RI]) backgroundProposalStateTransition( logger loghelper.LoggerWithContext, ogid OutcomeGenerationID, roundCtx RoundContext, - - stateTransitionInputsDigest StateTransitionInputsDigest, - writeSet []KeyValuePairWithDeletions, - stateRootDigest StateRootDigest, - reportsPlusPrecursor ocr3_1types.ReportsPlusPrecursor, - aq types.AttributedQuery, asos []AttributedSignedObservation, kvReadWriteTxn KeyValueDatabaseReadWriteTransaction, @@ -569,82 +476,60 @@ func (outgen *outcomeGenerationState[RI]) backgroundProposalStateTransition( } }() - if asos != nil { - - aos, ok := outgen.backgroundCheckAttributedSignedObservations(ctx, logger, ogid, roundCtx, aq, asos, kvReadWriteTxn) - if !ok { - return - } - reportsPlusPrecursor, ok = callPluginFromOutcomeGenerationBackground[ocr3_1types.ReportsPlusPrecursor]( - ctx, - logger, - "StateTransition", - 0, // StateTransition is a pure function and should finish "instantly" - roundCtx, - func(ctx context.Context, roundCtx RoundContext) (ocr3_1types.ReportsPlusPrecursor, error) { - return outgen.reportingPlugin.StateTransition( - ctx, + aos, ok := outgen.backgroundCheckAttributedSignedObservations(ctx, logger, ogid, roundCtx, aq, asos, kvReadWriteTxn) + if !ok { + return + } + reportsPlusPrecursor, ok := callPluginFromOutcomeGenerationBackground[ocr3_1types.ReportsPlusPrecursor]( + ctx, + logger, + "StateTransition", + outgen.config.WarnDurationStateTransition, + roundCtx, + func(ctx context.Context, roundCtx RoundContext) (ocr3_1types.ReportsPlusPrecursor, error) { + return outgen.reportingPlugin.StateTransition( + ctx, + roundCtx.SeqNr, + aq, + aos, + kvReadWriteTxn, + NewRoundBlobBroadcastFetcher( roundCtx.SeqNr, - aq, - aos, - kvReadWriteTxn, - NewRoundBlobBroadcastFetcher( - roundCtx.SeqNr, - outgen.blobBroadcastFetcher, - ), - ) - }, - ) - if !ok { - return - } - - stateTransitionInputsDigest = MakeStateTransitionInputsDigest( - ogid, - roundCtx.SeqNr, - aq, - aos, - ) + outgen.blobBroadcastFetcher, + ), + ) + }, + ) + if !ok { + return + } - var err error - writeSet, err = kvReadWriteTxn.GetWriteSet() - if err != nil { - outgen.logger.Warn("failed to get write set from kv read/write transaction", commontypes.LogFields{ - "seqNr": outgen.sharedState.seqNr, - "error": err, - }) - return - } - stateRootDigest, err = kvReadWriteTxn.CloseWriteSet() - if err != nil { - outgen.logger.Warn("failed to close the transaction WriteSet", commontypes.LogFields{ - "seqNr": outgen.sharedState.seqNr, - "error": err, - }) - return - } - } else { + stateTransitionInputsDigest := MakeStateTransitionInputsDigest( + outgen.config.ConfigDigest, + roundCtx.SeqNr, + aq, + aos, + ) - // apply write set instead of executing StateTransition - localStateRootDigest, err := kvReadWriteTxn.ApplyWriteSet(writeSet) - if err != nil { - outgen.logger.Warn("failed to apply write set to kv read/write transaction", commontypes.LogFields{ - "seqNr": outgen.sharedState.seqNr, - "error": err, - }) - return - } - if localStateRootDigest != stateRootDigest { - logger.Error("StateRootDigest mismatch", commontypes.LogFields{ - "localStateRootDigest": localStateRootDigest, - "receivedStateRootDigest": stateRootDigest, - }) - return - } + writeSet, err := kvReadWriteTxn.GetWriteSet() + if err != nil { + outgen.logger.Warn("failed to get write set from kv read/write transaction", commontypes.LogFields{ + "seqNr": outgen.sharedState.seqNr, + "error": err, + }) + return + } + stateRootDigest, err := kvReadWriteTxn.CloseWriteSet() + if err != nil { + outgen.logger.Warn("failed to close the transaction WriteSet", commontypes.LogFields{ + "seqNr": outgen.sharedState.seqNr, + "error": err, + }) + return } - stateTransitionOutputDigest := MakeStateTransitionOutputDigest(ogid, roundCtx.SeqNr, writeSet) - reportsPlusPrecursorDigest := MakeReportsPlusPrecursorDigest(ogid, roundCtx.SeqNr, reportsPlusPrecursor) + stateTransitionOutputDigest := MakeStateTransitionOutputDigest(outgen.config.ConfigDigest, roundCtx.SeqNr, writeSet) + reportsPlusPrecursorDigest := MakeReportsPlusPrecursorDigest(outgen.config.ConfigDigest, roundCtx.SeqNr, reportsPlusPrecursor) stateTransitionOutputs := StateTransitionOutputs{writeSet} @@ -653,13 +538,15 @@ func (outgen *outcomeGenerationState[RI]) backgroundProposalStateTransition( roundCtx.Epoch, roundCtx.SeqNr, kvReadWriteTxn, - stateTransitionInfo{ - stateTransitionInputsDigest, + stateTransitionInfoDigestsAndPreimages{ + stateTransitionInfoDigests{ + stateTransitionInputsDigest, + stateTransitionOutputDigest, + stateRootDigest, + reportsPlusPrecursorDigest, + }, stateTransitionOutputs, - stateTransitionOutputDigest, - stateRootDigest, reportsPlusPrecursor, - reportsPlusPrecursorDigest, }, }: shouldDiscardKVTxn = false @@ -687,32 +574,74 @@ func (outgen *outcomeGenerationState[RI]) eventComputedProposalStateTransition(e outgen.followerState.openKVTxn = ev.KeyValueDatabaseReadWriteTransaction + var stidap stateTransitionInfoDigestsAndPreimages + switch sti := ev.stateTransitionInfo.(type) { + case stateTransitionInfoDigestsAndPreimages: + stidap = sti + case stateTransitionInfoDigests: + outgen.logger.Critical("assumption violation, EventComputedProposalStateTransition state transition info contains only digests and no preimages", commontypes.LogFields{ + "seqNr": outgen.sharedState.seqNr, + }) + return + } + + outgen.followerState.stateTransitionInfo = stidap + + err := outgen.persistUnattestedStateTransitionBlockAndReportsPlusPrecursor( + StateTransitionBlock{ + ev.Epoch, + ev.SeqNr, + stidap.InputsDigest, + stidap.Outputs, + stidap.StateRootDigest, + stidap.ReportsPlusPrecursorDigest, + }, + stidap.InputsDigest, + stidap.ReportsPlusPrecursor, + ) + if err != nil { + outgen.logger.Error("failed to persist unattested state transition block and reports plus precursor", commontypes.LogFields{ + "seqNr": outgen.sharedState.seqNr, + "error": err, + }) + return + } + + outgen.broadcastMessagePrepare() +} + +// broadcasts MessagePrepare for outgen.sharedState.e, outgen.sharedState.seqNr +// and outgen.followerState.stateTransitionInfo +func (outgen *outcomeGenerationState[RI]) broadcastMessagePrepare() { + ogid := outgen.ID() + seqNr := outgen.sharedState.seqNr + stid := outgen.followerState.stateTransitionInfo.digests() prepareSignature, err := MakePrepareSignature( - outgen.ID(), - outgen.sharedState.seqNr, - ev.stateTransitionInfo.InputsDigest, - ev.stateTransitionInfo.OutputDigest, - ev.stateTransitionInfo.StateRootDigest, - ev.stateTransitionInfo.ReportsPlusPrecursorDigest, + ogid, + seqNr, + stid.InputsDigest, + stid.OutputDigest, + stid.StateRootDigest, + stid.ReportsPlusPrecursorDigest, outgen.offchainKeyring.OffchainSign, ) if err != nil { outgen.logger.Critical("failed to sign Prepare", commontypes.LogFields{ - "seqNr": outgen.sharedState.seqNr, + "seqNr": seqNr, "error": err, }) return } outgen.followerState.phase = outgenFollowerPhaseSentPrepare - outgen.followerState.stateTransitionInfo = ev.stateTransitionInfo outgen.logger.Debug("broadcasting MessagePrepare", commontypes.LogFields{ - "seqNr": outgen.sharedState.seqNr, + "seqNr": seqNr, + "phase": outgen.followerState.phase, }) outgen.netSender.Broadcast(MessagePrepare[RI]{ outgen.sharedState.e, - outgen.sharedState.seqNr, + seqNr, prepareSignature, }) } @@ -768,6 +697,8 @@ func (outgen *outcomeGenerationState[RI]) tryProcessPreparePool() { return } + stid := outgen.followerState.stateTransitionInfo.digests() + for sender, preparePoolEntry := range poolEntries { if preparePoolEntry.Verified != nil { continue @@ -775,10 +706,10 @@ func (outgen *outcomeGenerationState[RI]) tryProcessPreparePool() { err := preparePoolEntry.Item.Verify( outgen.ID(), outgen.sharedState.seqNr, - outgen.followerState.stateTransitionInfo.InputsDigest, - outgen.followerState.stateTransitionInfo.OutputDigest, - outgen.followerState.stateTransitionInfo.StateRootDigest, - outgen.followerState.stateTransitionInfo.ReportsPlusPrecursorDigest, + stid.InputsDigest, + stid.OutputDigest, + stid.StateRootDigest, + stid.ReportsPlusPrecursorDigest, outgen.config.OracleIdentities[sender].OffchainPublicKey, ) ok := err == nil @@ -812,10 +743,10 @@ func (outgen *outcomeGenerationState[RI]) tryProcessPreparePool() { commitSignature, err := MakeCommitSignature( outgen.ID(), outgen.sharedState.seqNr, - outgen.followerState.stateTransitionInfo.InputsDigest, - outgen.followerState.stateTransitionInfo.OutputDigest, - outgen.followerState.stateTransitionInfo.StateRootDigest, - outgen.followerState.stateTransitionInfo.ReportsPlusPrecursorDigest, + stid.InputsDigest, + stid.OutputDigest, + stid.StateRootDigest, + stid.ReportsPlusPrecursorDigest, outgen.offchainKeyring.OffchainSign, ) if err != nil { @@ -829,10 +760,10 @@ func (outgen *outcomeGenerationState[RI]) tryProcessPreparePool() { if !outgen.persistAndUpdateCertIfGreater(&CertifiedPrepare{ outgen.sharedState.e, outgen.sharedState.seqNr, - outgen.followerState.stateTransitionInfo.InputsDigest, - outgen.followerState.stateTransitionInfo.Outputs, - outgen.followerState.stateTransitionInfo.StateRootDigest, - outgen.followerState.stateTransitionInfo.ReportsPlusPrecursor, + stid.InputsDigest, + stid.OutputDigest, + stid.StateRootDigest, + stid.ReportsPlusPrecursorDigest, prepareQuorumCertificate, }) { return @@ -901,6 +832,8 @@ func (outgen *outcomeGenerationState[RI]) tryProcessCommitPool() { return } + stid := outgen.followerState.stateTransitionInfo.digests() + for sender, commitPoolEntry := range poolEntries { if commitPoolEntry.Verified != nil { continue @@ -908,10 +841,10 @@ func (outgen *outcomeGenerationState[RI]) tryProcessCommitPool() { err := commitPoolEntry.Item.Verify( outgen.ID(), outgen.sharedState.seqNr, - outgen.followerState.stateTransitionInfo.InputsDigest, - outgen.followerState.stateTransitionInfo.OutputDigest, - outgen.followerState.stateTransitionInfo.StateRootDigest, - outgen.followerState.stateTransitionInfo.ReportsPlusPrecursorDigest, + stid.InputsDigest, + stid.OutputDigest, + stid.StateRootDigest, + stid.ReportsPlusPrecursorDigest, outgen.config.OracleIdentities[sender].OffchainPublicKey, ) ok := err == nil @@ -946,25 +879,63 @@ func (outgen *outcomeGenerationState[RI]) tryProcessCommitPool() { outgen.metrics.ledCommittedRoundsTotal.Inc() } - persistedBlockAndCert := outgen.commit(CertifiedCommit{ + commitQC := &CertifiedCommit{ outgen.sharedState.e, outgen.sharedState.seqNr, - outgen.followerState.stateTransitionInfo.InputsDigest, - outgen.followerState.stateTransitionInfo.Outputs, - outgen.followerState.stateTransitionInfo.StateRootDigest, - outgen.followerState.stateTransitionInfo.ReportsPlusPrecursor, + stid.InputsDigest, + stid.OutputDigest, + stid.StateRootDigest, + stid.ReportsPlusPrecursorDigest, commitQuorumCertificate, - }) + } - if !persistedBlockAndCert { - outgen.logger.Error("failed to persist block/cert, stopping to not advance kv further than persisted blocks", commontypes.LogFields{ - "seqNr": outgen.sharedState.seqNr, - }) + switch sti := outgen.followerState.stateTransitionInfo.(type) { + case stateTransitionInfoDigests: + // We re-prepared + outgen.tryToMoveCertAndKVStateToCommitQC(commitQC) + case stateTransitionInfoDigestsAndPreimages: + // Regular round progression, we already should have an open transaction + persistedCert := outgen.commit(*commitQC) + if !persistedCert { + outgen.logger.Error("commit() failed to persist cert", commontypes.LogFields{ + "seqNr": outgen.sharedState.seqNr, + }) + return + } - return - } + if outgen.followerState.openKVTxn == nil { + outgen.logger.Error("no open kv transaction, unexpected", commontypes.LogFields{ + "seqNr": outgen.sharedState.seqNr, + "phase": outgen.followerState.phase, + }) + return + } + + // Write attested state transition block + { + stb := StateTransitionBlock{ + commitQC.CommitEpoch, + commitQC.CommitSeqNr, + sti.InputsDigest, + sti.Outputs, + sti.StateRootDigest, + sti.ReportsPlusPrecursorDigest, + } + astb := AttestedStateTransitionBlock{ + stb, + commitQC.CommitQuorumCertificate, + } + + err := outgen.followerState.openKVTxn.WriteAttestedStateTransitionBlock(commitQC.CommitSeqNr, astb) + if err != nil { + outgen.logger.Error("error writing attested state transition block", commontypes.LogFields{ + "seqNr": commitQC.CommitSeqNr, + "error": err, + }) + return + } + } - if outgen.followerState.openKVTxn != nil { err := outgen.followerState.openKVTxn.Commit() outgen.followerState.openKVTxn.Discard() outgen.followerState.openKVTxn = nil @@ -995,6 +966,14 @@ func (outgen *outcomeGenerationState[RI]) tryProcessCommitPool() { } } + if outgen.sharedState.committedSeqNr != commitQC.CommitSeqNr { + outgen.logger.Warn("could not move committed seq nr to commit qc, abandoning epoch", commontypes.LogFields{ + "commitSeqNr": commitQC.CommitSeqNr, + "committedSeqNr": outgen.sharedState.committedSeqNr, + }) + return + } + kvReadTxn, err := outgen.kvDb.NewReadTransaction(outgen.sharedState.seqNr + 1) if err != nil { outgen.logger.Warn("skipping call to ReportingPlugin.Committed", commontypes.LogFields{ @@ -1037,7 +1016,7 @@ func (outgen *outcomeGenerationState[RI]) backgroundCommitted( ctx, logger, "Committed", - 0, // Committed is a pure function and should finish "instantly" + outgen.config.WarnDurationCommitted, roundCtx, func(ctx context.Context, roundCtx RoundContext) (error, error) { return outgen.reportingPlugin.Committed(ctx, roundCtx.SeqNr, kvReadTxn), nil @@ -1083,9 +1062,8 @@ func (outgen *outcomeGenerationState[RI]) eventComputedCommitted(ev EventCompute } func (outgen *outcomeGenerationState[RI]) completeRound() { - if uint64(outgen.config.RMax) <= outgen.sharedState.seqNr-outgen.sharedState.firstSeqNrOfEpoch+1 { - outgen.logger.Debug("epoch has been going on for too long, sending EventChangeLeader to Pacemaker", commontypes.LogFields{ + outgen.logger.Debug("epoch has been going on for too long, sending EventNewEpochRequest to Pacemaker", commontypes.LogFields{ "firstSeqNrOfEpoch": outgen.sharedState.firstSeqNrOfEpoch, "seqNr": outgen.sharedState.seqNr, "rMax": outgen.config.RMax, @@ -1096,6 +1074,9 @@ func (outgen *outcomeGenerationState[RI]) completeRound() { return } return + } else if outgen.followerState.leaderAbdicated { + outgen.sendNewEpochRequestToPacemakerDueToLeaderAbdication() + return } else { outgen.logger.Debug("sending EventProgress to Pacemaker", commontypes.LogFields{ "seqNr": outgen.sharedState.seqNr, @@ -1115,35 +1096,31 @@ func (outgen *outcomeGenerationState[RI]) completeRound() { outgen.tryProcessRoundStartPool() } -func (outgen *outcomeGenerationState[RI]) commit(commit CertifiedCommit) (persistedBlockAndCert bool) { - if commit.SeqNr() < outgen.sharedState.committedSeqNr { - outgen.logger.Critical("assumption violation, commitSeqNr is less than committedSeqNr", commontypes.LogFields{ - "commitSeqNr": commit.SeqNr, - "committedSeqNr": outgen.sharedState.committedSeqNr, - }) - panic("") +func (outgen *outcomeGenerationState[RI]) sendNewEpochRequestToPacemakerDueToLeaderAbdication() { + outgen.logger.Debug("leader abdicated in MessageEpochStart, sending EventNewEpochRequest to Pacemaker", commontypes.LogFields{ + "firstSeqNrOfEpoch": outgen.sharedState.firstSeqNrOfEpoch, + "seqNr": outgen.sharedState.seqNr, + }) + select { + case outgen.chOutcomeGenerationToPacemaker <- EventNewEpochRequest[RI]{}: + case <-outgen.ctx.Done(): + return } +} +func (outgen *outcomeGenerationState[RI]) commit(commit CertifiedCommit) bool { if commit.SeqNr() <= outgen.sharedState.committedSeqNr { outgen.logger.Debug("skipping commit of already committed seqNr", commontypes.LogFields{ "commitSeqNr": commit.SeqNr(), "committedSeqNr": outgen.sharedState.committedSeqNr, }) - persistedBlockAndCert = true - goto ReapCompleted } else { // commit.SeqNr >= outgen.sharedState.committedSeqNr + 1 - if !outgen.persistCommitAsBlock(&commit) { - return - } - if !outgen.persistAndUpdateCertIfGreater(&commit) { - return + return false } - persistedBlockAndCert = true - outgen.sharedState.committedSeqNr = commit.SeqNr() outgen.metrics.committedSeqNr.Set(float64(commit.SeqNr())) @@ -1151,56 +1128,20 @@ func (outgen *outcomeGenerationState[RI]) commit(commit CertifiedCommit) (persis "seqNr": commit.SeqNr(), }) - if outgen.followerState.phase != outgenFollowerPhaseSentCommit { - outgen.logger.Debug("skipping notification of report attestation, we don't have the reports plus precursor locally", commontypes.LogFields{ - "committedSeqNr": outgen.sharedState.committedSeqNr, - "phase": outgen.followerState.phase, - }) - goto ReapCompleted - } - - reportsPlusPrecursor := outgen.followerState.stateTransitionInfo.ReportsPlusPrecursor - - if !bytes.Equal(reportsPlusPrecursor[:], commit.ReportsPlusPrecursor) { - outgen.logger.Critical("assumption violation, local reports plus precursor must match what is included in commit", commontypes.LogFields{ - "committedSeqNr": outgen.sharedState.committedSeqNr, - "reportsPlusPrecursorLocal": reportsPlusPrecursor, - "reportsPlusPrecursorCommit": commit.ReportsPlusPrecursor, - }) - panic("") - } - select { - case outgen.chOutcomeGenerationToReportAttestation <- EventCertifiedCommit[RI]{ - - CertifiedCommittedReports[RI]{ - commit.Epoch(), - commit.SeqNr(), - commit.StateTransitionInputsDigest, - MakeStateTransitionOutputDigest( - OutcomeGenerationID{ - outgen.config.ConfigDigest, - commit.Epoch(), - }, - commit.SeqNr(), - commit.StateTransitionOutputs.WriteSet, - ), - commit.StateRootDigest, - reportsPlusPrecursor, - commit.CommitQuorumCertificate, - }, + case outgen.chOutcomeGenerationToReportAttestation <- EventNewCertifiedCommit[RI]{ + commit.SeqNr(), + commit.ReportsPlusPrecursorDigest, }: case <-outgen.ctx.Done(): - return } } -ReapCompleted: outgen.followerState.roundStartPool.ReapCompleted(outgen.sharedState.committedSeqNr) outgen.followerState.proposalPool.ReapCompleted(outgen.sharedState.committedSeqNr) outgen.followerState.preparePool.ReapCompleted(outgen.sharedState.committedSeqNr) outgen.followerState.commitPool.ReapCompleted(outgen.sharedState.committedSeqNr) - return + return true } // Updates and persists cert if it is greater than the current cert. @@ -1245,8 +1186,7 @@ func (outgen *outcomeGenerationState[RI]) backgroundCheckAttributedSignedObserva ctx, logger, "ValidateObservation", - - 0, // ValidateObservation is a pure function and should finish "instantly" + outgen.config.WarnDurationValidateObservation, roundCtx, func(ctx context.Context, roundCtx RoundContext) (error, error) { return outgen.reportingPlugin.ValidateObservation( @@ -1349,7 +1289,7 @@ func (outgen *outcomeGenerationState[RI]) backgroundCheckAttributedSignedObserva ctx, logger, "ObservationQuorum", - 0, // ObservationQuorum is a pure function and should finish "instantly" + outgen.config.WarnDurationObservationQuorum, roundCtx, func(ctx context.Context, roundCtx RoundContext) (bool, error) { return outgen.reportingPlugin.ObservationQuorum( @@ -1384,58 +1324,7 @@ func (outgen *outcomeGenerationState[RI]) backgroundCheckAttributedSignedObserva return attributedObservations, true } -func (outgen *outcomeGenerationState[RI]) persistCommitAsBlock(commit *CertifiedCommit) bool { - - seqNr := commit.SeqNr() - astb := AttestedStateTransitionBlock{ - StateTransitionBlock{ - commit.Epoch(), - seqNr, - commit.StateTransitionInputsDigest, - commit.StateTransitionOutputs, - commit.StateRootDigest, - commit.ReportsPlusPrecursor, - }, - commit.CommitQuorumCertificate, - } - - tx, err := outgen.kvDb.NewUnserializedReadWriteTransactionUnchecked() - if err != nil { - outgen.logger.Error("error creating read transaction", commontypes.LogFields{ - "error": err, - }) - return false - } - defer tx.Discard() - - err = tx.WriteAttestedStateTransitionBlock(seqNr, astb) - if err != nil { - outgen.logger.Error("error writing attested state transition block", commontypes.LogFields{ - "seqNr": seqNr, - "error": err, - }) - return false - } - - err = tx.Commit() - if err != nil { - outgen.logger.Error("error committing transaction", commontypes.LogFields{ - "error": err, - }) - return false - } - - // persited now - outgen.logger.Trace("persisted block", commontypes.LogFields{ - "seqNr": seqNr, - }) - return true -} - func (outgen *outcomeGenerationState[RI]) refreshCommittedSeqNrAndCert() { - - preRefreshCommittedSeqNr := outgen.sharedState.committedSeqNr - tx, err := outgen.kvDb.NewReadTransactionUnchecked() if err != nil { outgen.logger.Error("error creating read transaction", commontypes.LogFields{ @@ -1445,39 +1334,27 @@ func (outgen *outcomeGenerationState[RI]) refreshCommittedSeqNrAndCert() { } defer tx.Discard() - postRefreshCommittedSeqNr, err := tx.ReadHighestCommittedSeqNr() + committedKVSeqNr, err := tx.ReadHighestCommittedSeqNr() if err != nil { - outgen.logger.Error("kvDb.HighestCommittedSeqNr() failed during refresh", commontypes.LogFields{ - "preRefreshCommittedSeqNr": preRefreshCommittedSeqNr, - "error": err, + outgen.logger.Error("tx.ReadHighestCommittedSeqNr() failed during refresh", commontypes.LogFields{ + "committedSeqNr": outgen.sharedState.committedSeqNr, + "error": err, }) return } logger := outgen.logger.MakeChild(commontypes.LogFields{ - "preRefreshCommittedSeqNr": preRefreshCommittedSeqNr, - "postRefreshCommittedSeqNr": postRefreshCommittedSeqNr, + "committedKVSeqNr": committedKVSeqNr, + "committedSeqNr": outgen.sharedState.committedSeqNr, }) - if postRefreshCommittedSeqNr == preRefreshCommittedSeqNr { - return - } else if postRefreshCommittedSeqNr+1 == preRefreshCommittedSeqNr { - - logger.Warn("last kv transaction commit failed, requesting state sync", nil) - select { - case outgen.chOutcomeGenerationToStateSync <- EventStateSyncRequest[RI]{ - preRefreshCommittedSeqNr, - }: - case <-outgen.ctx.Done(): - } + if committedKVSeqNr <= outgen.sharedState.committedSeqNr { + logger.Info("refresh: committedKVSeqNr <= outgen.sharedState.committedSeqNr, nothing to do", nil) return - } else if postRefreshCommittedSeqNr < preRefreshCommittedSeqNr { - logger.Critical("assumption violation, kv is way behind what outgen knows as committed", nil) - panic("") } - astb, err := tx.ReadAttestedStateTransitionBlock(postRefreshCommittedSeqNr) + astb, err := tx.ReadAttestedStateTransitionBlock(committedKVSeqNr) if err != nil { logger.Error("error reading attested state transition block during refresh", commontypes.LogFields{ "error": err, @@ -1488,102 +1365,30 @@ func (outgen *outcomeGenerationState[RI]) refreshCommittedSeqNrAndCert() { logger.Critical("assumption violation, attested state transition block for kv committed seq nr does not exist", nil) panic("") } - if astb.StateTransitionBlock.SeqNr() != postRefreshCommittedSeqNr { + if astb.StateTransitionBlock.SeqNr() != committedKVSeqNr { logger.Critical("assumption violation, attested state transition block has unexpected seq nr", commontypes.LogFields{ - "expectedSeqNr": postRefreshCommittedSeqNr, + "expectedSeqNr": committedKVSeqNr, "actualSeqNr": astb.StateTransitionBlock.SeqNr(), }) panic("") } - stb := astb.StateTransitionBlock - persistedBlockAndCert := outgen.commit(CertifiedCommit{ - stb.Epoch, - stb.SeqNr(), - stb.StateTransitionInputsDigest, - stb.StateTransitionOutputs, - stb.StateRootDigest, - stb.ReportsPlusPrecursor, - astb.AttributedCommitSignatures, - }) + persistedCert := outgen.commit(astb.ToCertifiedCommit(outgen.config.ConfigDigest)) - if !persistedBlockAndCert { + if !persistedCert { logger.Warn("outgen.commit() failed, aborting refresh", nil) return } - if outgen.sharedState.committedSeqNr != postRefreshCommittedSeqNr { - logger.Critical("assumption violation, outgen local committed seq nr did not progress even though we persisted block and cert", commontypes.LogFields{ - "expectedCommittedSeqNr": postRefreshCommittedSeqNr, + if outgen.sharedState.committedSeqNr != committedKVSeqNr { + logger.Critical("assumption violation, outgen local committed seq nr did not progress even though commit() succeeded", commontypes.LogFields{ + "expectedCommittedSeqNr": committedKVSeqNr, "actualCommittedSeqNr": outgen.sharedState.committedSeqNr, }) panic("") } - logger.Debug("refreshed cert", nil) -} - -func (outgen *outcomeGenerationState[RI]) ensureHighestCertifiedIsCompatible(highestCertified CertifiedPrepareOrCommit, name string) bool { - logger := outgen.logger - committedSeqNr := outgen.sharedState.committedSeqNr - - if highestCertified.IsGenesis() { - return true - } else if commitQC, ok := highestCertified.(*CertifiedCommit); ok { - commitQcSeqNr := commitQC.SeqNr() - if commitQcSeqNr == committedSeqNr { - - } else if commitQcSeqNr > committedSeqNr { - - logger.Warn("dropping "+name+" because we are behind (commitQc)", commontypes.LogFields{ - "commitQcSeqNr": commitQcSeqNr, - "committedSeqNr": committedSeqNr, - }) - - return false - } else { - - logger.Warn("dropping "+name+" because we are ahead (commitQc)", commontypes.LogFields{ - "commitQcSeqNr": commitQcSeqNr, - "committedSeqNr": committedSeqNr, - }) - return false - } - } else { - // We're dealing with a re-proposal from a failed epoch - - prepareQc, ok := highestCertified.(*CertifiedPrepare) - if !ok { - logger.Critical("cast to CertifiedPrepare failed while processing "+name, commontypes.LogFields{ - "seqNr": outgen.sharedState.seqNr, - }) - return false - } - - committedSeqNr := outgen.sharedState.committedSeqNr - prepareQcSeqNr := prepareQc.SeqNr() - - if prepareQcSeqNr == committedSeqNr+1 { - - } else if prepareQcSeqNr == committedSeqNr { - - } else if prepareQcSeqNr > committedSeqNr+1 { - - logger.Warn("dropping "+name+" because we are behind (prepareQc)", commontypes.LogFields{ - "prepareQcSeqNr": prepareQcSeqNr, - "committedSeqNr": committedSeqNr, - }) - return false - } else { - - logger.Warn("dropping "+name+" because we are ahead (prepareQc)", commontypes.LogFields{ - "prepareQcSeqNr": prepareQcSeqNr, - "committedSeqNr": committedSeqNr, - }) - return false - } - } - return true + logger.Debug("refreshed committed seq nr and cert", nil) } func (outgen *outcomeGenerationState[RI]) ensureOpenKVTransactionDiscarded() { diff --git a/offchainreporting2plus/internal/ocr3_1/protocol/outcome_generation_leader.go b/offchainreporting2plus/internal/ocr3_1/protocol/outcome_generation_leader.go index 3f4065f6..91a310bf 100644 --- a/offchainreporting2plus/internal/ocr3_1/protocol/outcome_generation_leader.go +++ b/offchainreporting2plus/internal/ocr3_1/protocol/outcome_generation_leader.go @@ -25,7 +25,6 @@ const ( ) func (outgen *outcomeGenerationState[RI]) messageEpochStartRequest(msg MessageEpochStartRequest[RI], sender commontypes.OracleID) { - outgen.logger.Debug("received MessageEpochStartRequest", commontypes.LogFields{ "sender": sender, "msgHighestCertifiedTimestamp": msg.SignedHighestCertifiedTimestamp.HighestCertifiedTimestamp, @@ -153,13 +152,6 @@ func (outgen *outcomeGenerationState[RI]) messageEpochStartRequest(msg MessageEp highestCertifiedProof, } - outgen.refreshCommittedSeqNrAndCert() - if !outgen.ensureHighestCertifiedIsCompatible(maxRequest.message.HighestCertified, "potential broadcast of EpochStartProof") { - outgen.leaderState.phase = outgenLeaderPhaseAbdicate - - return - } - // This is a sanity check to ensure that we only construct epochStartProofs that are actually valid. // This should never fail. if err := epochStartProof.Verify(outgen.ID(), outgen.config.OracleIdentities, outgen.config.ByzQuorumSize()); err != nil { @@ -170,30 +162,50 @@ func (outgen *outcomeGenerationState[RI]) messageEpochStartRequest(msg MessageEp return } + outgen.sendStateSyncRequestFromCertifiedPrepareOrCommit(epochStartProof.HighestCertified) + + abdicate := !outgen.couldLeaderCreateProposalInEpoch(epochStartProof.HighestCertified) + outgen.refreshCommittedSeqNrAndCert() // call in case stasy has made progress in the meanwhile + outgen.leaderState.phase = outgenLeaderPhaseSentEpochStart outgen.logger.Info("broadcasting MessageEpochStart", commontypes.LogFields{ "contributors": contributors, "highestCertifiedTimestamp": epochStartProof.HighestCertified.Timestamp(), "highestCertifiedQCSeqNr": epochStartProof.HighestCertified.SeqNr(), + "abdicate": abdicate, }) outgen.netSender.Broadcast(MessageEpochStart[RI]{ outgen.sharedState.e, epochStartProof, + abdicate, }) + if abdicate { + outgen.leaderState.phase = outgenLeaderPhaseAbdicate + // Receipt of our own MessageEpochStart will cause the follower logic to + // handle HighestCertified despite this early return. + return + } + if epochStartProof.HighestCertified.IsGenesis() { outgen.sharedState.firstSeqNrOfEpoch = outgen.sharedState.committedSeqNr + 1 outgen.startSubsequentLeaderRound() } else if commitQC, ok := epochStartProof.HighestCertified.(*CertifiedCommit); ok { - - if commitQC.SeqNr() != outgen.sharedState.committedSeqNr { - outgen.logger.Critical("assumption violation, we should have already committed the seqNr of the commitQC", commontypes.LogFields{ - "seqNr": outgen.sharedState.seqNr, - "commitSeqNr": commitQC.SeqNr(), + // Try to commit the block corresponding to the commitQC if (1) we have + // not done so and (2) if we have all available information present, + // i.e. the StateTransitionBlock corresponding to the commitQC is + // available. + outgen.tryToMoveCertAndKVStateToCommitQC(commitQC) + if outgen.sharedState.committedSeqNr != commitQC.CommitSeqNr { + + outgen.logger.Warn("cannot process MessageEpochStartRequest, mismatching committedSeqNr, silently abdicating for this epoch", commontypes.LogFields{ + "commitSeqNr": commitQC.CommitSeqNr, + "committedSeqNr": outgen.sharedState.committedSeqNr, }) - panic("") + outgen.leaderState.phase = outgenLeaderPhaseAbdicate + return } outgen.sharedState.firstSeqNrOfEpoch = outgen.sharedState.committedSeqNr + 1 outgen.startSubsequentLeaderRound() @@ -203,6 +215,17 @@ func (outgen *outcomeGenerationState[RI]) messageEpochStartRequest(msg MessageEp outgen.logger.Critical("cast to CertifiedPrepare failed while processing MessageEpochStartRequest", nil) return } + + if prepareQc.SeqNr() < outgen.sharedState.committedSeqNr { + + outgen.logger.Warn("cannot process MessageEpochStartRequest, prepareQC seqNr is less than committedSeqNr, silently abdicating for this epoch", commontypes.LogFields{ + "prepareQCSeqNr": prepareQc.SeqNr(), + "committedSeqNr": outgen.sharedState.committedSeqNr, + }) + outgen.leaderState.phase = outgenLeaderPhaseAbdicate + return + } + outgen.sharedState.firstSeqNrOfEpoch = prepareQc.SeqNr() + 1 // We're dealing with a re-proposal from a failed epoch based on a // prepare qc. @@ -210,6 +233,60 @@ func (outgen *outcomeGenerationState[RI]) messageEpochStartRequest(msg MessageEp } } +func (outgen *outcomeGenerationState[RI]) couldLeaderCreateProposalInEpoch(highestCertified CertifiedPrepareOrCommit) bool { + var ( + highestCertifiedSeqNr uint64 + highestCertifiedStateTransitionInputsDigest StateTransitionInputsDigest + ) + + switch cpoc := highestCertified.(type) { + case *CertifiedCommit: + highestCertifiedSeqNr = cpoc.CommitSeqNr + highestCertifiedStateTransitionInputsDigest = cpoc.StateTransitionInputsDigest + case *CertifiedPrepare: + highestCertifiedSeqNr = cpoc.PrepareSeqNr + highestCertifiedStateTransitionInputsDigest = cpoc.StateTransitionInputsDigest + } + + tx, err := outgen.kvDb.NewReadTransactionUnchecked() + if err != nil { + outgen.logger.Error("failed to create read transaction, can't drive epoch", commontypes.LogFields{ + "highestCertifiedSeqNr": highestCertifiedSeqNr, + "error": err, + }) + return false + } + defer tx.Discard() + + committedKVSeqNr, err := tx.ReadHighestCommittedSeqNr() + if err != nil { + outgen.logger.Error("failed to read highest committed kv seq nr, can't drive epoch", commontypes.LogFields{ + "highestCertifiedSeqNr": highestCertifiedSeqNr, + "error": err, + }) + return false + } + + if committedKVSeqNr == highestCertifiedSeqNr { + return true + } + if committedKVSeqNr+1 != highestCertifiedSeqNr { + return false + } + unattestedExists, err := tx.ExistsUnattestedStateTransitionBlock(highestCertifiedSeqNr, highestCertifiedStateTransitionInputsDigest) + if err != nil { + outgen.logger.Error("failed to check if unattested state transition block exists, can't drive epoch", commontypes.LogFields{ + "highestCertifiedSeqNr": highestCertifiedSeqNr, + "error": err, + }) + return false + } + if unattestedExists { + return true + } + return false +} + func (outgen *outcomeGenerationState[RI]) eventTRoundTimeout() { outgen.logger.Debug("TRound fired", commontypes.LogFields{ "seqNr": outgen.sharedState.seqNr, @@ -246,6 +323,7 @@ func (outgen *outcomeGenerationState[RI]) startSubsequentLeaderRound() { "seqNr": outgen.sharedState.seqNr, "error": err, }) + return } outgen.subs.Go(func() { @@ -264,7 +342,7 @@ func (outgen *outcomeGenerationState[RI]) backgroundQuery( ctx, logger, "Query", - outgen.config.MaxDurationQuery, + outgen.config.WarnDurationQuery, roundCtx, func(ctx context.Context, outctx RoundContext) (types.Query, error) { return outgen.reportingPlugin.Query( @@ -428,7 +506,7 @@ func (outgen *outcomeGenerationState[RI]) backgroundVerifyValidateObservation( ctx, logger, "ValidateObservation", - 0, // ValidateObservation is a pure function and should finish "instantly" + outgen.config.WarnDurationValidateObservation, roundCtx, func(ctx context.Context, roundCtx RoundContext) (error, error) { return outgen.reportingPlugin.ValidateObservation(ctx, @@ -548,7 +626,7 @@ func (outgen *outcomeGenerationState[RI]) backgroundObservationQuorum( ctx, logger, "ObservationQuorum", - 0, // ObservationQuorum is a pure function and should finish "instantly" + outgen.config.WarnDurationObservationQuorum, roundCtx, func(ctx context.Context, roundCtx RoundContext) (bool, error) { return outgen.reportingPlugin.ObservationQuorum( diff --git a/offchainreporting2plus/internal/ocr3_1/protocol/outcome_generation_reap.go b/offchainreporting2plus/internal/ocr3_1/protocol/outcome_generation_reap.go new file mode 100644 index 00000000..4c441e37 --- /dev/null +++ b/offchainreporting2plus/internal/ocr3_1/protocol/outcome_generation_reap.go @@ -0,0 +1,88 @@ +package protocol + +import ( + "context" + "fmt" + "time" + + "github.com/smartcontractkit/libocr/commontypes" + "github.com/smartcontractkit/libocr/internal/loghelper" +) + +const ( + unattestedStateTransitionBlockFetchingReapInterval = 5 * time.Second + + maxUnattestedStateTransitionBlocksToReapInOneGo = 100_000 +) + +func reapUnattestedBlocks(ctx context.Context, kvDb KeyValueDatabase, logger commontypes.Logger) error { + committedKVSeqNr, err := committedKVSeqNr(kvDb) + if err != nil { + return fmt.Errorf("failed to read highest committed kv seq nr: %w", err) + } + + logger.Info("RunOutcomeGenerationReap: reaping unattested state transition blocks", commontypes.LogFields{ + "committedKVSeqNr": committedKVSeqNr, + }) + + for { + done, err := reapSomeUnattestedBlocks(kvDb, committedKVSeqNr) + if err != nil { + return err + } + + if ctx.Err() != nil { + return ctx.Err() + } + + if done { + break + } + } + return nil +} + +func reapSomeUnattestedBlocks(kvDb KeyValueDatabase, committedKVSeqNr uint64) (done bool, err error) { + kvTxn, err := kvDb.NewUnserializedReadWriteTransactionUnchecked() + if err != nil { + return false, fmt.Errorf("failed to open unserialized transaction: %w", err) + } + defer kvTxn.Discard() + + done, err = kvTxn.DeleteUnattestedStateTransitionBlocks(committedKVSeqNr, maxUnattestedStateTransitionBlocksToReapInOneGo) + if err != nil { + return false, fmt.Errorf("failed to delete unattested state transition blocks: %w", err) + } + err = kvTxn.Commit() + if err != nil { + return false, fmt.Errorf("failed to commit: %w", err) + } + return done, err +} + +func RunOutcomeGenerationReap( + ctx context.Context, + logger loghelper.LoggerWithContext, + kvDb KeyValueDatabase, +) { + chDone := ctx.Done() + ticker := time.NewTicker(unattestedStateTransitionBlockFetchingReapInterval) + defer ticker.Stop() + + for { + select { + case <-ticker.C: + case <-chDone: + return + } + + logger.Info("RunOutcomeGenerationReap: calling reapUnattestedBlocks", nil) + err := reapUnattestedBlocks(ctx, kvDb, logger) + if err != nil { + logger.Warn("RunOutcomeGenerationReap: failed to reap unattested state transition blocks. Will retry soon.", commontypes.LogFields{ + "error": err, + "waitBeforeRetry": unattestedStateTransitionBlockFetchingReapInterval.String(), + }) + } + } +} diff --git a/offchainreporting2plus/internal/ocr3_1/protocol/pacemaker.go b/offchainreporting2plus/internal/ocr3_1/protocol/pacemaker.go index a30b815f..f80ad8a9 100644 --- a/offchainreporting2plus/internal/ocr3_1/protocol/pacemaker.go +++ b/offchainreporting2plus/internal/ocr3_1/protocol/pacemaker.go @@ -12,7 +12,7 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/smartcontractkit/libocr/commontypes" "github.com/smartcontractkit/libocr/internal/loghelper" - "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3config" + "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config" "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/smartcontractkit/libocr/permutation" ) @@ -23,7 +23,7 @@ func RunPacemaker[RI any]( chNetToPacemaker <-chan MessageToPacemakerWithSender[RI], chPacemakerToOutcomeGeneration chan<- EventToOutcomeGeneration[RI], chOutcomeGenerationToPacemaker <-chan EventToPacemaker[RI], - config ocr3config.SharedConfig, + config ocr3_1config.SharedConfig, database Database, id commontypes.OracleID, localConfig types.LocalConfig, @@ -50,7 +50,7 @@ func makePacemakerState[RI any]( chNetToPacemaker <-chan MessageToPacemakerWithSender[RI], chPacemakerToOutcomeGeneration chan<- EventToOutcomeGeneration[RI], chOutcomeGenerationToPacemaker <-chan EventToPacemaker[RI], - config ocr3config.SharedConfig, + config ocr3_1config.SharedConfig, database Database, id commontypes.OracleID, localConfig types.LocalConfig, logger loghelper.LoggerWithContext, @@ -85,7 +85,7 @@ type pacemakerState[RI any] struct { chNetToPacemaker <-chan MessageToPacemakerWithSender[RI] chPacemakerToOutcomeGeneration chan<- EventToOutcomeGeneration[RI] chOutcomeGenerationToPacemaker <-chan EventToPacemaker[RI] - config ocr3config.SharedConfig + config ocr3_1config.SharedConfig database Database id commontypes.OracleID localConfig types.LocalConfig @@ -194,7 +194,7 @@ func (pace *pacemakerState[RI]) eventProgress() { func (pace *pacemakerState[RI]) sendNewEpochWish() { pace.netSender.Broadcast(MessageNewEpochWish[RI]{pace.ne}) - pace.tResend = time.After(pace.config.DeltaResend) + pace.tResend = time.After(pace.config.GetDeltaResend()) } func (pace *pacemakerState[RI]) eventTResendTimeout() { diff --git a/offchainreporting2plus/internal/ocr3_1/protocol/report_attestation.go b/offchainreporting2plus/internal/ocr3_1/protocol/report_attestation.go index f33a7443..3df251ca 100644 --- a/offchainreporting2plus/internal/ocr3_1/protocol/report_attestation.go +++ b/offchainreporting2plus/internal/ocr3_1/protocol/report_attestation.go @@ -3,6 +3,7 @@ package protocol import ( "context" "crypto/rand" + "fmt" "math" "math/big" "runtime" @@ -14,7 +15,7 @@ import ( "github.com/smartcontractkit/libocr/internal/loghelper" "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/common" "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/common/scheduler" - "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3config" + "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config" "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3_1types" "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3types" "github.com/smartcontractkit/libocr/offchainreporting2plus/types" @@ -28,20 +29,21 @@ func RunReportAttestation[RI any]( chOutcomeGenerationToReportAttestation <-chan EventToReportAttestation[RI], chReportAttestationToStateSync chan<- EventToStateSync[RI], chReportAttestationToTransmission chan<- EventToTransmission[RI], - config ocr3config.SharedConfig, + config ocr3_1config.SharedConfig, contractTransmitter ocr3types.ContractTransmitter[RI], + kvDb KeyValueDatabase, logger loghelper.LoggerWithContext, netSender NetworkSender[RI], onchainKeyring ocr3types.OnchainKeyring[RI], reportingPlugin ocr3_1types.ReportingPlugin[RI], ) { - sched := scheduler.NewScheduler[EventMissingOutcome[RI]]() + sched := scheduler.NewScheduler[EventMissingReportsPlusPrecursor[RI]]() defer sched.Close() newReportAttestationState(ctx, chNetToReportAttestation, chOutcomeGenerationToReportAttestation, chReportAttestationToStateSync, chReportAttestationToTransmission, - config, contractTransmitter, logger, netSender, onchainKeyring, + config, contractTransmitter, kvDb, logger, netSender, onchainKeyring, reportingPlugin, sched).run() } @@ -53,6 +55,8 @@ const lookaheadMinRounds int = 4 const lookaheadDuration = 30 * time.Second const lookaheadMaxRounds int = 10 +const maxReportsPlusPrecursorsToReapInOneGo = 100_000 + type reportAttestationState[RI any] struct { ctx context.Context subs subprocesses.Subprocesses @@ -61,14 +65,15 @@ type reportAttestationState[RI any] struct { chOutcomeGenerationToReportAttestation <-chan EventToReportAttestation[RI] chReportAttestationToStateSync chan<- EventToStateSync[RI] chReportAttestationToTransmission chan<- EventToTransmission[RI] - config ocr3config.SharedConfig + config ocr3_1config.SharedConfig contractTransmitter ocr3types.ContractTransmitter[RI] + kvDb KeyValueDatabase logger loghelper.LoggerWithContext netSender NetworkSender[RI] onchainKeyring ocr3types.OnchainKeyring[RI] reportingPlugin ocr3_1types.ReportingPlugin[RI] - scheduler *scheduler.Scheduler[EventMissingOutcome[RI]] + scheduler *scheduler.Scheduler[EventMissingReportsPlusPrecursor[RI]] chLocalEvent chan EventComputedReports[RI] // reap() is used to prevent unbounded state growth of rounds. @@ -82,23 +87,26 @@ type reportAttestationState[RI any] struct { } type round[RI any] struct { - ctx context.Context // should always be initialized when a round[RI] is initiated - ctxCancel context.CancelFunc // should always be initialized when a round[RI] is initiated - verifiedCertifiedCommit *CertifiedCommittedReports[RI] // only stores certifiedCommit whose qc has been verified - reportsPlus *[]ocr3types.ReportPlus[RI] // cache result of ReportingPlugin.Reports(certifiedCommit.SeqNr, certifiedCommit.Outcome) - oracles []oracle // always initialized to be of length n - startedFetch bool - complete bool + ctx context.Context // should always be initialized when a round[RI] is initiated + ctxCancel context.CancelFunc // should always be initialized when a round[RI] is initiated + certifiedReportsPlusPrecursorDigest *ReportsPlusPrecursorDigest // only stores ReportsPlusPrecursorDigest when supplied as committed by outgen, or from f+1 matching MessageReportSignatures + certifiedReportsPlusPrecursor *ocr3_1types.ReportsPlusPrecursor // only stores ReportsPlusPrecursor when it is the valid preimage of certifiedReportsPlusPrecursorDigest + reportsPlus *[]ocr3types.ReportPlus[RI] // cache result of ReportingPlugin.Reports(seqNr, certifiedReportsPlusPrecursor) + oracles []oracle // always initialized to be of length n + startedFetch bool + successfullyCheckedKV bool + complete bool } // oracle contains information about interactions with oracles (self & others) type oracle struct { - signatures [][]byte - sentSignatures bool - validSignatures *bool - weRequested bool - theyServiced bool - weServiced bool + signatures [][]byte + reportsPlusPrecursorDigest *ReportsPlusPrecursorDigest + sentSignatures bool + validSignatures *bool + weRequested bool + theyServiced bool + weServiced bool } func (repatt *reportAttestationState[RI]) run() { @@ -130,6 +138,38 @@ func (repatt *reportAttestationState[RI]) run() { } } +func (repatt *reportAttestationState[RI]) eventNewCertifiedCommit(ev EventNewCertifiedCommit[RI]) { + repatt.receivedCertifiedReportsPlusPrecursorDigest(ev.SeqNr, ev.ReportsPlusPrecursorDigest) +} + +func (repatt *reportAttestationState[RI]) receivedCertifiedReportsPlusPrecursorDigest(seqNr uint64, reportsPlusPrecursorDigest ReportsPlusPrecursorDigest) { + if repatt.rounds[seqNr] != nil && repatt.rounds[seqNr].certifiedReportsPlusPrecursorDigest != nil { + repatt.logger.Debug("dropping redundant ReportsPlusPrecursorDigest", commontypes.LogFields{ + "seqNr": seqNr, + }) + return + } + + if _, ok := repatt.rounds[seqNr]; !ok { + ctx, cancel := context.WithCancel(repatt.ctx) + repatt.rounds[seqNr] = &round[RI]{ + ctx, + cancel, + nil, + nil, + nil, + make([]oracle, repatt.config.N()), + false, + false, + false, + } + } + + repatt.rounds[seqNr].certifiedReportsPlusPrecursorDigest = &reportsPlusPrecursorDigest + + repatt.tryComplete(seqNr) +} + func (repatt *reportAttestationState[RI]) messageReportSignatures( msg MessageReportSignatures[RI], sender commontypes.OracleID, @@ -164,9 +204,11 @@ func (repatt *reportAttestationState[RI]) messageReportSignatures( cancel, nil, nil, + nil, make([]oracle, repatt.config.N()), false, false, + false, } } @@ -179,18 +221,19 @@ func (repatt *reportAttestationState[RI]) messageReportSignatures( } repatt.rounds[msg.SeqNr].oracles[sender].signatures = msg.ReportSignatures + repatt.rounds[msg.SeqNr].oracles[sender].reportsPlusPrecursorDigest = &msg.ReportsPlusPrecursorDigest repatt.rounds[msg.SeqNr].oracles[sender].sentSignatures = true repatt.tryComplete(msg.SeqNr) } -func (repatt *reportAttestationState[RI]) eventMissingOutcome(ev EventMissingOutcome[RI]) { - repatt.logger.Debug("received EventMissingOutcome", commontypes.LogFields{ +func (repatt *reportAttestationState[RI]) eventMissingReportsPlusPrecursor(ev EventMissingReportsPlusPrecursor[RI]) { + repatt.logger.Debug("received EventMissingReportsPlusPrecursor", commontypes.LogFields{ "msgSeqNr": ev.SeqNr, }) if repatt.rounds[ev.SeqNr] == nil { - repatt.logger.Debug("dropping EventMissingOutcome for unknown seqNr", commontypes.LogFields{ + repatt.logger.Debug("dropping EventMissingReportsPlusPrecursor for unknown seqNr", commontypes.LogFields{ "evSeqNr": ev.SeqNr, "highWaterMark": repatt.highWaterMark, "expiryRounds": repatt.expiryRounds(), @@ -198,24 +241,28 @@ func (repatt *reportAttestationState[RI]) eventMissingOutcome(ev EventMissingOut return } - if repatt.rounds[ev.SeqNr].verifiedCertifiedCommit != nil { - repatt.logger.Debug("dropping EventMissingOutcome, already have Outcome", commontypes.LogFields{ + if repatt.rounds[ev.SeqNr].certifiedReportsPlusPrecursor != nil { + repatt.logger.Debug("dropping EventMissingReportsPlusPrecursor, already have ReportsPlusPrecursor", commontypes.LogFields{ "evSeqNr": ev.SeqNr, }) return } - repatt.tryRequestCertifiedCommit(ev.SeqNr) + if repatt.tryReadReportsPlusPrecursor(ev.SeqNr) { + return + } + + repatt.tryRequestReportsPlusPrecursor(ev.SeqNr) } -func (repatt *reportAttestationState[RI]) messageCertifiedCommitRequest(msg MessageCertifiedCommitRequest[RI], sender commontypes.OracleID) { - repatt.logger.Debug("received MessageCertifiedCommitRequest", commontypes.LogFields{ +func (repatt *reportAttestationState[RI]) messageReportsPlusPrecursorRequest(msg MessageReportsPlusPrecursorRequest[RI], sender commontypes.OracleID) { + repatt.logger.Debug("received MessageReportsPlusPrecursorRequest", commontypes.LogFields{ "sender": sender, "msgSeqNr": msg.SeqNr, }) if repatt.rounds[msg.SeqNr] == nil { - repatt.logger.Debug("dropping MessageCertifiedCommitRequest for unknown seqNr", commontypes.LogFields{ + repatt.logger.Debug("dropping MessageReportsPlusPrecursorRequest for unknown seqNr", commontypes.LogFields{ "msgSeqNr": msg.SeqNr, "sender": sender, "highWaterMark": repatt.highWaterMark, @@ -224,8 +271,8 @@ func (repatt *reportAttestationState[RI]) messageCertifiedCommitRequest(msg Mess return } - if repatt.rounds[msg.SeqNr].verifiedCertifiedCommit == nil { - repatt.logger.Debug("dropping MessageCertifiedCommitRequest for outcome with unknown certified commit", commontypes.LogFields{ + if repatt.rounds[msg.SeqNr].certifiedReportsPlusPrecursor == nil { + repatt.logger.Debug("dropping MessageReportsPlusPrecursorRequest for seqNr with unknown certified reports plus precursor", commontypes.LogFields{ "msgSeqNr": msg.SeqNr, "sender": sender, }) @@ -233,7 +280,7 @@ func (repatt *reportAttestationState[RI]) messageCertifiedCommitRequest(msg Mess } if repatt.rounds[msg.SeqNr].oracles[sender].weServiced { - repatt.logger.Warn("dropping duplicate MessageCertifiedCommitRequest", commontypes.LogFields{ + repatt.logger.Warn("dropping duplicate MessageReportsPlusPrecursorRequest", commontypes.LogFields{ "msgSeqNr": msg.SeqNr, "sender": sender, }) @@ -242,21 +289,24 @@ func (repatt *reportAttestationState[RI]) messageCertifiedCommitRequest(msg Mess repatt.rounds[msg.SeqNr].oracles[sender].weServiced = true - repatt.logger.Debug("sending MessageCertifiedCommit", commontypes.LogFields{ + repatt.logger.Debug("sending MessageReportsPlusPrecursor", commontypes.LogFields{ "msgSeqNr": msg.SeqNr, "to": sender, }) - repatt.netSender.SendTo(MessageCertifiedCommit[RI]{*repatt.rounds[msg.SeqNr].verifiedCertifiedCommit}, sender) + repatt.netSender.SendTo(MessageReportsPlusPrecursor[RI]{ + msg.SeqNr, + *repatt.rounds[msg.SeqNr].certifiedReportsPlusPrecursor, + }, sender) } -func (repatt *reportAttestationState[RI]) messageCertifiedCommit(msg MessageCertifiedCommit[RI], sender commontypes.OracleID) { - repatt.logger.Debug("received MessageCertifiedCommit", commontypes.LogFields{ +func (repatt *reportAttestationState[RI]) messageReportsPlusPrecursor(msg MessageReportsPlusPrecursor[RI], sender commontypes.OracleID) { + repatt.logger.Debug("received MessageReportsPlusPrecursor", commontypes.LogFields{ "sender": sender, - "msgSeqNr": msg.CertifiedCommittedReports.SeqNr, + "msgSeqNr": msg.SeqNr, }) - if repatt.rounds[msg.CertifiedCommittedReports.SeqNr] == nil { - repatt.logger.Warn("dropping MessageCertifiedCommit for unknown seqNr", commontypes.LogFields{ - "msgSeqNr": msg.CertifiedCommittedReports.SeqNr, + if repatt.rounds[msg.SeqNr] == nil { + repatt.logger.Warn("dropping MessageReportsPlusPrecursor for unknown seqNr", commontypes.LogFields{ + "msgSeqNr": msg.SeqNr, "sender": sender, "highWaterMark": repatt.highWaterMark, "expiryRounds": repatt.expiryRounds(), @@ -264,10 +314,10 @@ func (repatt *reportAttestationState[RI]) messageCertifiedCommit(msg MessageCert return } - oracle := &repatt.rounds[msg.CertifiedCommittedReports.SeqNr].oracles[sender] + oracle := &repatt.rounds[msg.SeqNr].oracles[sender] if !(oracle.weRequested && !oracle.theyServiced) { - repatt.logger.Warn("dropping unexpected MessageCertifiedCommit", commontypes.LogFields{ - "msgSeqNr": msg.CertifiedCommittedReports.SeqNr, + repatt.logger.Warn("dropping unexpected MessageReportsPlusPrecursor", commontypes.LogFields{ + "msgSeqNr": msg.SeqNr, "sender": sender, "weRequested": oracle.weRequested, "theyServiced": oracle.theyServiced, @@ -277,36 +327,40 @@ func (repatt *reportAttestationState[RI]) messageCertifiedCommit(msg MessageCert oracle.theyServiced = true - if repatt.rounds[msg.CertifiedCommittedReports.SeqNr].verifiedCertifiedCommit != nil { - repatt.logger.Debug("dropping redundant MessageCertifiedCommit", commontypes.LogFields{ - "msgSeqNr": msg.CertifiedCommittedReports.SeqNr, + if repatt.rounds[msg.SeqNr].certifiedReportsPlusPrecursor != nil { + repatt.logger.Debug("dropping redundant MessageReportsPlusPrecursor", commontypes.LogFields{ + "msgSeqNr": msg.SeqNr, "sender": sender, }) return } - if err := msg.CertifiedCommittedReports.Verify(repatt.config.ConfigDigest, repatt.config.OracleIdentities, repatt.config.ByzQuorumSize()); err != nil { - repatt.logger.Warn("dropping MessageCertifiedCommit with invalid certified commit", commontypes.LogFields{ - "msgSeqNr": msg.CertifiedCommittedReports.SeqNr, - "sender": sender, + expectedReportsPlusPrecursorDigest := *repatt.rounds[msg.SeqNr].certifiedReportsPlusPrecursorDigest + actualReportsPlusPrecursorDigest := MakeReportsPlusPrecursorDigest( + repatt.config.ConfigDigest, + msg.SeqNr, + msg.ReportsPlusPrecursor, + ) + + if expectedReportsPlusPrecursorDigest != actualReportsPlusPrecursorDigest { + repatt.logger.Warn("dropping MessageReportsPlusPrecursor with mismatching digest", commontypes.LogFields{ + "msgSeqNr": msg.SeqNr, + "sender": sender, + "expectedReportsPlusPrecursorDigest": expectedReportsPlusPrecursorDigest, + "actualReportsPlusPrecursorDigest": actualReportsPlusPrecursorDigest, }) return } - repatt.logger.Debug("received valid MessageCertifiedCommit", commontypes.LogFields{ - "msgSeqNr": msg.CertifiedCommittedReports.SeqNr, + repatt.logger.Debug("received valid MessageReportsPlusPrecursor", commontypes.LogFields{ + "msgSeqNr": msg.SeqNr, "sender": sender, }) - repatt.receivedVerifiedCertifiedCommit(msg.CertifiedCommittedReports) - - //select { - //case repatt.chReportAttestationToOutcomeGeneration <- EventCertifiedCommit[RI]{msg.CertifiedCommit}: - //case <-repatt.ctx.Done(): - //} + repatt.receivedCertifiedReportsPlusPrecursor(msg.SeqNr, msg.ReportsPlusPrecursor) } -func (repatt *reportAttestationState[RI]) tryRequestCertifiedCommit(seqNr uint64) { +func (repatt *reportAttestationState[RI]) tryRequestReportsPlusPrecursor(seqNr uint64) { candidates := make([]commontypes.OracleID, 0, repatt.config.N()) for oracleID, oracle := range repatt.rounds[seqNr].oracles { // avoid duplicate requests @@ -314,7 +368,7 @@ func (repatt *reportAttestationState[RI]) tryRequestCertifiedCommit(seqNr uint64 continue } // avoid requesting from oracles that haven't sent MessageReportSignatures - if len(oracle.signatures) == 0 { + if !oracle.sentSignatures { continue } candidates = append(candidates, commontypes.OracleID(oracleID)) @@ -334,12 +388,12 @@ func (repatt *reportAttestationState[RI]) tryRequestCertifiedCommit(seqNr uint64 } randomCandidate := candidates[int(randomIndex.Int64())] repatt.rounds[seqNr].oracles[randomCandidate].weRequested = true - repatt.logger.Debug("sending MessageCertifiedCommitRequest", commontypes.LogFields{ + repatt.logger.Debug("sending MessageReportsPlusPrecursorRequest", commontypes.LogFields{ "seqNr": seqNr, "to": randomCandidate, }) - repatt.netSender.SendTo(MessageCertifiedCommitRequest[RI]{seqNr}, randomCandidate) - repatt.scheduler.ScheduleDelay(EventMissingOutcome[RI]{seqNr}, repatt.config.DeltaCertifiedCommitRequest) + repatt.netSender.SendTo(MessageReportsPlusPrecursorRequest[RI]{seqNr}, randomCandidate) + repatt.scheduler.ScheduleDelay(EventMissingReportsPlusPrecursor[RI]{seqNr}, repatt.config.GetDeltaReportsPlusPrecursorRequest()) } func (repatt *reportAttestationState[RI]) tryComplete(seqNr uint64) { @@ -350,32 +404,57 @@ func (repatt *reportAttestationState[RI]) tryComplete(seqNr uint64) { return } - if repatt.rounds[seqNr].verifiedCertifiedCommit == nil { - oraclesThatSentSignatures := 0 + if repatt.rounds[seqNr].certifiedReportsPlusPrecursorDigest == nil { + // check if we received sufficient MessageReportSignatures of which f+1 have matching ReportsPlusPrecursorDigest + + oraclesThatSentReportsPlusPrecursorDigest := make(map[ReportsPlusPrecursorDigest]int) + maxOraclesThatSentReportsPlusPrecursorDigest := 0 for _, oracle := range repatt.rounds[seqNr].oracles { if !oracle.sentSignatures { continue } - oraclesThatSentSignatures++ + rppd := *oracle.reportsPlusPrecursorDigest + oraclesThatSentReportsPlusPrecursorDigest[rppd]++ + maxOraclesThatSentReportsPlusPrecursorDigest = max( + maxOraclesThatSentReportsPlusPrecursorDigest, + oraclesThatSentReportsPlusPrecursorDigest[rppd], + ) + if oraclesThatSentReportsPlusPrecursorDigest[rppd] > repatt.config.F { + repatt.rounds[seqNr].certifiedReportsPlusPrecursorDigest = &rppd + break + } } - if oraclesThatSentSignatures <= repatt.config.F { - repatt.logger.Debug("cannot complete, missing CertifiedCommit and signatures", commontypes.LogFields{ - "oraclesThatSentSignatures": oraclesThatSentSignatures, - "seqNr": seqNr, - "threshold": repatt.config.F + 1, + if maxOraclesThatSentReportsPlusPrecursorDigest <= repatt.config.F { + repatt.logger.Debug("cannot complete, missing certified ReportsPlusPrecursorDigest and signatures", commontypes.LogFields{ + "maxOraclesThatSentReportsPlusPrecursorDigest": maxOraclesThatSentReportsPlusPrecursorDigest, + "seqNr": seqNr, + "threshold": repatt.config.F + 1, }) - } else if !repatt.rounds[seqNr].startedFetch { - repatt.logger.Debug("we have received f+1 MessageReportSignatures messages but we are still missing CertifiedCommit", commontypes.LogFields{ - "seqNr": seqNr, - }) - repatt.rounds[seqNr].startedFetch = true - repatt.scheduler.ScheduleDelay(EventMissingOutcome[RI]{seqNr}, repatt.config.DeltaCertifiedCommitRequest) + return + } else { + // We found the certified ReportsPlusPrecursorDigest through f+1 + // MessageReportSignatures, which means that we did not find out + // through EventNewCertifiedCommit of outcome generation select { case repatt.chReportAttestationToStateSync <- EventStateSyncRequest[RI]{seqNr}: case <-repatt.ctx.Done(): } } + } + + if repatt.rounds[seqNr].certifiedReportsPlusPrecursorDigest != nil && repatt.rounds[seqNr].certifiedReportsPlusPrecursor == nil { + if repatt.tryReadReportsPlusPrecursor(seqNr) { + return + } + + if !repatt.rounds[seqNr].startedFetch { + repatt.logger.Debug("we have received the certified ReportsPlusPrecursorDigest but we are still missing ReportsPlusPrecursor", commontypes.LogFields{ + "seqNr": seqNr, + }) + repatt.rounds[seqNr].startedFetch = true + repatt.scheduler.ScheduleDelay(EventMissingReportsPlusPrecursor[RI]{seqNr}, repatt.config.GetDeltaReportsPlusPrecursorRequest()) + } return } @@ -392,7 +471,7 @@ func (repatt *reportAttestationState[RI]) tryComplete(seqNr uint64) { var aossPerReport [][]types.AttributedOnchainSignature = make([][]types.AttributedOnchainSignature, len(reportsPlus)) for oracleID := range repatt.rounds[seqNr].oracles { oracle := &repatt.rounds[seqNr].oracles[oracleID] - if len(oracle.signatures) == 0 { + if !oracle.sentSignatures { continue } if oracle.validSignatures == nil { @@ -503,50 +582,48 @@ func (repatt *reportAttestationState[RI]) verifySignatures(publicKey types.Oncha return allValid } -func (repatt *reportAttestationState[RI]) eventCertifiedCommit(ev EventCertifiedCommit[RI]) { - repatt.receivedVerifiedCertifiedCommit(ev.CertifiedCommittedReports) -} - -func (repatt *reportAttestationState[RI]) receivedVerifiedCertifiedCommit(certifiedCommit CertifiedCommittedReports[RI]) { - if repatt.rounds[certifiedCommit.SeqNr] != nil && repatt.rounds[certifiedCommit.SeqNr].verifiedCertifiedCommit != nil { - repatt.logger.Debug("dropping redundant CertifiedCommit", commontypes.LogFields{ - "seqNr": certifiedCommit.SeqNr, +func (repatt *reportAttestationState[RI]) receivedCertifiedReportsPlusPrecursor(seqNr uint64, reportsPlusPrecursor ocr3_1types.ReportsPlusPrecursor) { + if repatt.rounds[seqNr] != nil && repatt.rounds[seqNr].certifiedReportsPlusPrecursor != nil { + repatt.logger.Debug("dropping redundant certified ReportsPlusPrecursor", commontypes.LogFields{ + "seqNr": seqNr, }) return } - if _, ok := repatt.rounds[certifiedCommit.SeqNr]; !ok { + if _, ok := repatt.rounds[seqNr]; !ok { ctx, cancel := context.WithCancel(repatt.ctx) - repatt.rounds[certifiedCommit.SeqNr] = &round[RI]{ + repatt.rounds[seqNr] = &round[RI]{ ctx, cancel, nil, nil, + nil, make([]oracle, repatt.config.N()), false, false, + false, } } - repatt.rounds[certifiedCommit.SeqNr].verifiedCertifiedCommit = &certifiedCommit + repatt.rounds[seqNr].certifiedReportsPlusPrecursor = &reportsPlusPrecursor { - ctx := repatt.rounds[certifiedCommit.SeqNr].ctx + ctx := repatt.rounds[seqNr].ctx repatt.subs.Go(func() { - repatt.backgroundComputeReports(ctx, certifiedCommit) + repatt.backgroundComputeReports(ctx, seqNr, reportsPlusPrecursor) }) } } -func (repatt *reportAttestationState[RI]) backgroundComputeReports(ctx context.Context, verifiedCertifiedCommit CertifiedCommittedReports[RI]) { +func (repatt *reportAttestationState[RI]) backgroundComputeReports(ctx context.Context, seqNr uint64, certifiedReportsPlusPrecursor ocr3_1types.ReportsPlusPrecursor) { reportsPlus, ok := common.CallPluginFromBackground( ctx, repatt.logger, - commontypes.LogFields{"seqNr": verifiedCertifiedCommit.SeqNr}, + commontypes.LogFields{"seqNr": seqNr}, "Reports", 0, // Reports is a pure function and should finish "instantly" func(ctx context.Context) ([]ocr3types.ReportPlus[RI], error) { - return repatt.reportingPlugin.Reports(ctx, verifiedCertifiedCommit.SeqNr, verifiedCertifiedCommit.ReportsPlusPrecursor) + return repatt.reportingPlugin.Reports(ctx, seqNr, certifiedReportsPlusPrecursor) }, ) if !ok { @@ -554,12 +631,12 @@ func (repatt *reportAttestationState[RI]) backgroundComputeReports(ctx context.C } repatt.logger.Debug("successfully invoked ReportingPlugin.Reports", commontypes.LogFields{ - "seqNr": verifiedCertifiedCommit.SeqNr, + "seqNr": seqNr, "reports": len(reportsPlus), }) select { - case repatt.chLocalEvent <- EventComputedReports[RI]{verifiedCertifiedCommit.SeqNr, reportsPlus}: + case repatt.chLocalEvent <- EventComputedReports[RI]{seqNr, reportsPlus}: case <-ctx.Done(): return } @@ -601,14 +678,59 @@ func (repatt *reportAttestationState[RI]) eventComputedReports(ev EventComputedR "evSeqNr": ev.SeqNr, }) + reportsPlusPrecursorDigest := *repatt.rounds[ev.SeqNr].certifiedReportsPlusPrecursorDigest + repatt.netSender.Broadcast(MessageReportSignatures[RI]{ ev.SeqNr, sigs, + reportsPlusPrecursorDigest, }) // no need to call tryComplete since receipt of our own MessageReportSignatures will do so } +func (repatt *reportAttestationState[RI]) tryReadReportsPlusPrecursor(seqNr uint64) bool { + if repatt.rounds[seqNr] == nil || repatt.rounds[seqNr].certifiedReportsPlusPrecursor != nil { + return false + } + + if !repatt.rounds[seqNr].successfullyCheckedKV { + reportsPlusPrecursor, err := repatt.readReportsPlusPrecursor(seqNr, *repatt.rounds[seqNr].certifiedReportsPlusPrecursorDigest) + if err != nil { + repatt.logger.Warn("error reading ReportsPlusPrecursor from kv", commontypes.LogFields{ + "seqNr": seqNr, + "error": err, + }) + return false + } + + repatt.rounds[seqNr].successfullyCheckedKV = true + if reportsPlusPrecursor != nil { + repatt.receivedCertifiedReportsPlusPrecursor(seqNr, *reportsPlusPrecursor) + return true + } else { + repatt.logger.Warn("did not find ReportsPlusPrecursor in kv", commontypes.LogFields{ + "seqNr": seqNr, + "reportsPlusPrecursorDigest": *repatt.rounds[seqNr].certifiedReportsPlusPrecursorDigest, + }) + } + } + return false +} + +func (repatt *reportAttestationState[RI]) readReportsPlusPrecursor(seqNr uint64, reportsPlusPrecursorDigest ReportsPlusPrecursorDigest) (*ocr3_1types.ReportsPlusPrecursor, error) { + tx, err := repatt.kvDb.NewReadTransactionUnchecked() + if err != nil { + return nil, fmt.Errorf("error creating read transaction: %w", err) + } + defer tx.Discard() + reportsPlusPrecursor, err := tx.ReadReportsPlusPrecursor(seqNr, reportsPlusPrecursorDigest) + if err != nil { + return nil, fmt.Errorf("error reading reports plus precursor: %w", err) + } + return reportsPlusPrecursor, nil +} + // reap expired rounds if there is a new high water mark func (repatt *reportAttestationState[RI]) tryReap(seqNr uint64, sender commontypes.OracleID) { if repatt.highestReportSignaturesSeqNr[sender] >= seqNr { @@ -634,12 +756,16 @@ func (repatt *reportAttestationState[RI]) tryReap(seqNr uint64, sender commontyp repatt.reap() } -func (repatt *reportAttestationState[RI]) isBeyondExpiry(seqNr uint64) bool { +func (repatt *reportAttestationState[RI]) minUnexpiredSeqNr() uint64 { expiry := uint64(repatt.expiryRounds()) if repatt.highWaterMark <= expiry { - return false + return 0 } - return seqNr < repatt.highWaterMark-expiry + return repatt.highWaterMark - expiry +} + +func (repatt *reportAttestationState[RI]) isBeyondExpiry(seqNr uint64) bool { + return seqNr < repatt.minUnexpiredSeqNr() } func (repatt *reportAttestationState[RI]) isBeyondLookahead(seqNr uint64) bool { @@ -671,6 +797,13 @@ func (repatt *reportAttestationState[RI]) reap() { } } + { + minUnexpiredSeqNr := repatt.minUnexpiredSeqNr() + repatt.subs.Go(func() { + repatt.backgroundReapReportsPlusPrecursors(minUnexpiredSeqNr) + }) + } + repatt.logger.Debug("reaped expired rounds", commontypes.LogFields{ "before": beforeRounds, "after": len(repatt.rounds), @@ -678,6 +811,42 @@ func (repatt *reportAttestationState[RI]) reap() { }) } +func (repatt *reportAttestationState[RI]) backgroundReapReportsPlusPrecursors(minUnexpiredSeqNr uint64) { + done := false + for !done { + var err error + done, err = repatt.reapReportsPlusPrecursors(minUnexpiredSeqNr) + if err != nil { + repatt.logger.Warn("failed to reap reportsPlusPrecursors", commontypes.LogFields{ + "error": err, + }) + return + } + } + repatt.logger.Debug("successfully reaped reportsPlusPrecursors", commontypes.LogFields{ + "minUnexpiredSeqNr": minUnexpiredSeqNr, + }) +} + +func (repatt *reportAttestationState[RI]) reapReportsPlusPrecursors(minUnexpiredSeqNr uint64) (done bool, err error) { + tx, err := repatt.kvDb.NewUnserializedReadWriteTransactionUnchecked() + if err != nil { + return false, fmt.Errorf("failed to create transaction: %w", err) + } + defer tx.Discard() + + done, err = tx.DeleteReportsPlusPrecursors(minUnexpiredSeqNr, maxReportsPlusPrecursorsToReapInOneGo) + if err != nil { + return false, err + } + + err = tx.Commit() + if err != nil { + return false, fmt.Errorf("failed to commit: %w", err) + } + return done, err +} + // The age (denoted in rounds) after which a report is considered expired and // will automatically be dropped func (repatt *reportAttestationState[RI]) expiryRounds() int { @@ -711,13 +880,14 @@ func newReportAttestationState[RI any]( chOutcomeGenerationToReportAttestation <-chan EventToReportAttestation[RI], chReportAttestationToStateSync chan<- EventToStateSync[RI], chReportAttestationToTransmission chan<- EventToTransmission[RI], - config ocr3config.SharedConfig, + config ocr3_1config.SharedConfig, contractTransmitter ocr3types.ContractTransmitter[RI], + kvDb KeyValueDatabase, logger loghelper.LoggerWithContext, netSender NetworkSender[RI], onchainKeyring ocr3types.OnchainKeyring[RI], reportingPlugin ocr3_1types.ReportingPlugin[RI], - sched *scheduler.Scheduler[EventMissingOutcome[RI]], + sched *scheduler.Scheduler[EventMissingReportsPlusPrecursor[RI]], ) *reportAttestationState[RI] { return &reportAttestationState[RI]{ ctx, @@ -729,6 +899,7 @@ func newReportAttestationState[RI any]( chReportAttestationToTransmission, config, contractTransmitter, + kvDb, logger.MakeUpdated(commontypes.LogFields{"proto": "repatt"}), netSender, onchainKeyring, diff --git a/offchainreporting2plus/internal/ocr3_1/protocol/requestergadget/requester_gadget.go b/offchainreporting2plus/internal/ocr3_1/protocol/requestergadget/requester_gadget.go index 5075a5d5..4c33b2ea 100644 --- a/offchainreporting2plus/internal/ocr3_1/protocol/requestergadget/requester_gadget.go +++ b/offchainreporting2plus/internal/ocr3_1/protocol/requestergadget/requester_gadget.go @@ -7,12 +7,10 @@ import ( "time" "github.com/smartcontractkit/libocr/commontypes" + "github.com/smartcontractkit/libocr/offchainreporting2plus/types" ) -type RequestInfo struct { - // If no response is received by this time, the request is considered timed out. - ExpiryTimestamp time.Time -} +type RequestInfo = types.RequestInfo func NewRequesterGadget[Item comparable]( n int, @@ -42,7 +40,7 @@ func NewRequesterGadget[Item comparable]( // PleaseRecheckPendingItems must be called by the protocol when the output of // getPendingItemsFn or getSeedersFn has changed. func (rg *RequesterGadget[Item]) PleaseRecheckPendingItems() { - rg.chTick = time.After(0) + rg.chTick = time.After(minNextTickInterval) } // CheckAndMarkResponse must be called by the protocol when a response is @@ -107,6 +105,9 @@ func (rg *RequesterGadget[Item]) rankedSeeders(seeders map[commontypes.OracleID] } scoredSeeders := make([]scoredSeeder, 0, len(seeders)) for seeder := range seeders { + if _, ok := rg.oracles[seeder]; !ok { + continue + } if _, ok := excluded[seeder]; ok { continue } @@ -131,7 +132,10 @@ func (rg *RequesterGadget[Item]) Ticker() <-chan time.Time { return rg.chTick } -const maxNextTickInterval = 15 * time.Second +const ( + minNextTickInterval = 500 * time.Microsecond + maxNextTickInterval = 15 * time.Second +) func (rg *RequesterGadget[Item]) Tick() { @@ -162,7 +166,15 @@ func (rg *RequesterGadget[Item]) Tick() { if pendingRequest.expiryTimestamp.Before(now) { // Previous request timed out. rg.markTimedOutResponse(item, pendingRequest.seeder) + pendingItemState.pendingRequestOrNil = nil shouldRequestNow = true + } else { + // Previous request is still unexpired, wait for it. + nextTickForThisRequest := pendingItemState.pendingRequestOrNil.expiryTimestamp + if nextTickForThisRequest.Before(nextTick) { + nextTick = nextTickForThisRequest + } + shouldRequestNow = false } } else { shouldRequestNow = true @@ -183,44 +195,42 @@ func (rg *RequesterGadget[Item]) Tick() { rankedNonExcludedSeeders = rg.rankedSeeders(seeders, pendingItemState.temporarilyExcludedSeeders) } + nextTickForThisRequest := now.Add(maxNextTickInterval) + for _, seeder := range rankedNonExcludedSeeders { if rg.oracles[seeder].nextPossibleSendTimestamp.After(now) { + nextTickForThisRequest = minTime(nextTickForThisRequest, rg.oracles[seeder].nextPossibleSendTimestamp) continue } // try sending to this oracle requestInfo, ok := rg.sendRequestFn(item, seeder) if !ok { + + nextTickForThisRequest = now.Add(rg.requestInterval) continue } - rg.oracles[seeder].nextPossibleSendTimestamp = now.Add(rg.requestInterval) + rg.oracles[seeder].nextPossibleSendTimestamp = time.Now().Add(rg.requestInterval) pendingItemState.pendingRequestOrNil = &pendingRequest{ seeder, requestInfo.ExpiryTimestamp, } + nextTickForThisRequest = requestInfo.ExpiryTimestamp break } - var nextTickForThisRequest time.Time - if pendingItemState.pendingRequestOrNil != nil { - // We sent a request in this tick, but want to recheck in case of - // timeout. - nextTickForThisRequest = pendingItemState.pendingRequestOrNil.expiryTimestamp - } else if len(rankedNonExcludedSeeders) > 0 { - // We didn't manage to send a request in this tick, so want to send - // a request in the next tick, preferably to the best ranked seeder. - // No guarantee we'll be able to get to them first though, prior - // pending requests in the list will have priority. - nextTickForThisRequest = rg.oracles[rankedNonExcludedSeeders[0]].nextPossibleSendTimestamp // <= now.Add(rg.requestInterval) - } - - if nextTickForThisRequest.Before(nextTick) { - nextTick = nextTickForThisRequest - } + nextTick = minTime(nextTick, nextTickForThisRequest) } - rg.chTick = time.After(time.Until(nextTick)) + rg.chTick = time.After(max(minNextTickInterval, time.Until(nextTick))) +} + +func minTime(a time.Time, b time.Time) time.Time { + if a.Before(b) { + return a + } + return b } // A RequesterGadget helps us track and send requests for some data diff --git a/offchainreporting2plus/internal/ocr3_1/protocol/requestergadget/shuffle.go b/offchainreporting2plus/internal/ocr3_1/protocol/requestergadget/shuffle.go index 35089a75..bdb6b7e8 100644 --- a/offchainreporting2plus/internal/ocr3_1/protocol/requestergadget/shuffle.go +++ b/offchainreporting2plus/internal/ocr3_1/protocol/requestergadget/shuffle.go @@ -2,7 +2,7 @@ package requestergadget import ( "math" - "math/rand" + "math/rand/v2" "github.com/smartcontractkit/libocr/commontypes" ) diff --git a/offchainreporting2plus/internal/ocr3_1/protocol/signed_data.go b/offchainreporting2plus/internal/ocr3_1/protocol/signed_data.go index 838a2942..7b91dad1 100644 --- a/offchainreporting2plus/internal/ocr3_1/protocol/signed_data.go +++ b/offchainreporting2plus/internal/ocr3_1/protocol/signed_data.go @@ -102,15 +102,14 @@ type AttributedSignedObservation struct { type StateTransitionInputsDigest [32]byte func MakeStateTransitionInputsDigest( - ogid OutcomeGenerationID, + configDigest types.ConfigDigest, seqNr uint64, attributedQuery types.AttributedQuery, attributedObservations []types.AttributedObservation, ) StateTransitionInputsDigest { h := sha256.New() - _, _ = h.Write(ogid.ConfigDigest[:]) - _ = binary.Write(h, binary.BigEndian, ogid.Epoch) + _, _ = h.Write(configDigest[:]) _ = binary.Write(h, binary.BigEndian, seqNr) @@ -135,11 +134,10 @@ func MakeStateTransitionInputsDigest( type StateTransitionOutputDigest [32]byte -func MakeStateTransitionOutputDigest(ogid OutcomeGenerationID, seqNr uint64, output []KeyValuePairWithDeletions) StateTransitionOutputDigest { +func MakeStateTransitionOutputDigest(configDigest types.ConfigDigest, seqNr uint64, output []KeyValuePairWithDeletions) StateTransitionOutputDigest { h := sha256.New() - _, _ = h.Write(ogid.ConfigDigest[:]) - _ = binary.Write(h, binary.BigEndian, ogid.Epoch) + _, _ = h.Write(configDigest[:]) _ = binary.Write(h, binary.BigEndian, seqNr) @@ -160,11 +158,10 @@ func MakeStateTransitionOutputDigest(ogid OutcomeGenerationID, seqNr uint64, out type ReportsPlusPrecursorDigest [32]byte -func MakeReportsPlusPrecursorDigest(ogid OutcomeGenerationID, seqNr uint64, precursor ocr3_1types.ReportsPlusPrecursor) ReportsPlusPrecursorDigest { +func MakeReportsPlusPrecursorDigest(configDigest types.ConfigDigest, seqNr uint64, precursor ocr3_1types.ReportsPlusPrecursor) ReportsPlusPrecursorDigest { h := sha256.New() - _, _ = h.Write(ogid.ConfigDigest[:]) - _ = binary.Write(h, binary.BigEndian, ogid.Epoch) + _, _ = h.Write(configDigest[:]) _ = binary.Write(h, binary.BigEndian, seqNr) @@ -466,13 +463,13 @@ type CertifiedPrepareOrCommit interface { var _ CertifiedPrepareOrCommit = &CertifiedPrepare{} type CertifiedPrepare struct { - PrepareEpoch uint64 - PrepareSeqNr uint64 - StateTransitionInputsDigest StateTransitionInputsDigest - StateTransitionOutputs StateTransitionOutputs - StateRootDigest StateRootDigest - ReportsPlusPrecursor ocr3_1types.ReportsPlusPrecursor - PrepareQuorumCertificate []AttributedPrepareSignature + PrepareEpoch uint64 + PrepareSeqNr uint64 + StateTransitionInputsDigest StateTransitionInputsDigest + StateTransitionOutputsDigest StateTransitionOutputDigest + StateRootDigest StateRootDigest + ReportsPlusPrecursorDigest ReportsPlusPrecursorDigest + PrepareQuorumCertificate []AttributedPrepareSignature } func (hc *CertifiedPrepare) isCertifiedPrepareOrCommit() {} @@ -520,19 +517,9 @@ func (hc *CertifiedPrepare) Verify( if !(0 <= int(aps.Signer) && int(aps.Signer) < len(oracleIdentities)) { return fmt.Errorf("signer out of bounds: %v", aps.Signer) } - outputDigest := MakeStateTransitionOutputDigest( - ogid, - hc.SeqNr(), - hc.StateTransitionOutputs.WriteSet, - ) - reportsPlusPrecursorDigest := MakeReportsPlusPrecursorDigest( - ogid, - hc.SeqNr(), - hc.ReportsPlusPrecursor, - ) if err := aps.Signature.Verify( - ogid, hc.SeqNr(), hc.StateTransitionInputsDigest, outputDigest, hc.StateRootDigest, - reportsPlusPrecursorDigest, oracleIdentities[aps.Signer].OffchainPublicKey); err != nil { + ogid, hc.SeqNr(), hc.StateTransitionInputsDigest, hc.StateTransitionOutputsDigest, hc.StateRootDigest, + hc.ReportsPlusPrecursorDigest, oracleIdentities[aps.Signer].OffchainPublicKey); err != nil { return fmt.Errorf("%v-th signature by %v-th oracle with pubkey %x does not verify: %w", i, aps.Signer, oracleIdentities[aps.Signer].OffchainPublicKey, err) } } @@ -547,12 +534,6 @@ func (hc *CertifiedPrepare) CheckSize(n int, f int, limits ocr3_1types.Reporting return false } } - if !checkWriteSetSize(hc.StateTransitionOutputs.WriteSet, limits) { - return false - } - if len(hc.ReportsPlusPrecursor) > limits.MaxReportsPlusPrecursorLength { - return false - } return true } @@ -560,13 +541,13 @@ var _ CertifiedPrepareOrCommit = &CertifiedCommit{} // The empty CertifiedCommit{} is the genesis value type CertifiedCommit struct { - CommitEpoch uint64 - CommitSeqNr uint64 - StateTransitionInputsDigest StateTransitionInputsDigest - StateTransitionOutputs StateTransitionOutputs - StateRootDigest StateRootDigest - ReportsPlusPrecursor ocr3_1types.ReportsPlusPrecursor - CommitQuorumCertificate []AttributedCommitSignature + CommitEpoch uint64 + CommitSeqNr uint64 + StateTransitionInputsDigest StateTransitionInputsDigest + StateTransitionOutputsDigest StateTransitionOutputDigest + StateRootDigest StateRootDigest + ReportsPlusPrecursorDigest ReportsPlusPrecursorDigest + CommitQuorumCertificate []AttributedCommitSignature } func (hc *CertifiedCommit) isCertifiedPrepareOrCommit() {} @@ -590,11 +571,12 @@ func (hc *CertifiedCommit) Timestamp() HighestCertifiedTimestamp { func (hc *CertifiedCommit) IsGenesis() bool { // We intentionally don't just compare with CertifiedCommit{}, because after // protobuf deserialization, we might end up with hc.Outcome = []byte{} - return hc.Epoch() == uint64(0) && - hc.SeqNr() == uint64(0) && + return hc.CommitEpoch == uint64(0) && + hc.CommitSeqNr == uint64(0) && hc.StateTransitionInputsDigest == StateTransitionInputsDigest{} && + hc.StateTransitionOutputsDigest == StateTransitionOutputDigest{} && hc.StateRootDigest == StateRootDigest{} && - len(hc.ReportsPlusPrecursor) == 0 && + hc.ReportsPlusPrecursorDigest == ReportsPlusPrecursorDigest{} && len(hc.CommitQuorumCertificate) == 0 } @@ -625,22 +607,12 @@ func (hc *CertifiedCommit) Verify( if !(0 <= int(acs.Signer) && int(acs.Signer) < len(oracleIdentities)) { return fmt.Errorf("signer out of bounds: %v", acs.Signer) } - outputDigest := MakeStateTransitionOutputDigest( - ogid, - hc.SeqNr(), - hc.StateTransitionOutputs.WriteSet, - ) - reportsPlusPrecursorDigest := MakeReportsPlusPrecursorDigest( - ogid, - hc.SeqNr(), - hc.ReportsPlusPrecursor, - ) if err := acs.Signature.Verify(ogid, hc.SeqNr(), hc.StateTransitionInputsDigest, - outputDigest, + hc.StateTransitionOutputsDigest, hc.StateRootDigest, - reportsPlusPrecursorDigest, + hc.ReportsPlusPrecursorDigest, oracleIdentities[acs.Signer].OffchainPublicKey); err != nil { return fmt.Errorf("%v-th signature by %v-th oracle does not verify: %w", i, acs.Signer, err) } @@ -661,12 +633,6 @@ func (hc *CertifiedCommit) CheckSize(n int, f int, limits ocr3_1types.ReportingP return false } } - if !checkWriteSetSize(hc.StateTransitionOutputs.WriteSet, limits) { - return false - } - if len(hc.ReportsPlusPrecursor) > limits.MaxReportsPlusPrecursorLength { - return false - } return true } @@ -676,7 +642,7 @@ type StateTransitionBlock struct { StateTransitionInputsDigest StateTransitionInputsDigest StateTransitionOutputs StateTransitionOutputs StateRootDigest StateRootDigest - ReportsPlusPrecursor ocr3_1types.ReportsPlusPrecursor + ReportsPlusPrecursorDigest ReportsPlusPrecursorDigest } func (stb *StateTransitionBlock) SeqNr() uint64 { @@ -684,20 +650,24 @@ func (stb *StateTransitionBlock) SeqNr() uint64 { } func checkWriteSetSize(writeSet []KeyValuePairWithDeletions, limits ocr3_1types.ReportingPluginLimits) bool { + if len(writeSet) > limits.MaxKeyValueModifiedKeys { + return false + } + modifiedKeysPlusValuesLength := 0 for _, kvPair := range writeSet { - if len(kvPair.Key) > ocr3_1types.MaxMaxKeyValueKeyLength { + if len(kvPair.Key) > ocr3_1types.MaxMaxKeyValueKeyBytes { return false } if kvPair.Deleted && len(kvPair.Value) > 0 { return false } - if len(kvPair.Value) > ocr3_1types.MaxMaxKeyValueValueLength { + if len(kvPair.Value) > ocr3_1types.MaxMaxKeyValueValueBytes { return false } modifiedKeysPlusValuesLength += len(kvPair.Key) + len(kvPair.Value) } - if modifiedKeysPlusValuesLength > limits.MaxKeyValueModifiedKeysPlusValuesLength { + if modifiedKeysPlusValuesLength > limits.MaxKeyValueModifiedKeysPlusValuesBytes { return false } return true @@ -707,9 +677,6 @@ func (stb *StateTransitionBlock) CheckSize(limits ocr3_1types.ReportingPluginLim if !checkWriteSetSize(stb.StateTransitionOutputs.WriteSet, limits) { return false } - if len(stb.ReportsPlusPrecursor) > limits.MaxReportsPlusPrecursorLength { - return false - } return true } @@ -735,127 +702,31 @@ func (astb *AttestedStateTransitionBlock) Verify( oracleIdentities []config.OracleIdentity, byzQuorumSize int, ) error { - if byzQuorumSize != len(astb.AttributedCommitSignatures) { - return fmt.Errorf("wrong number of signatures, expected %d for byz. quorum but got %d", byzQuorumSize, len(astb.AttributedCommitSignatures)) - } - - ogid := OutcomeGenerationID{ - configDigest, - astb.StateTransitionBlock.Epoch, - } - seqNr := astb.StateTransitionBlock.SeqNr() - - seen := make(map[commontypes.OracleID]bool) - for i, sig := range astb.AttributedCommitSignatures { - if seen[sig.Signer] { - return fmt.Errorf("duplicate signature by %v", sig.Signer) - } - seen[sig.Signer] = true - if !(0 <= int(sig.Signer) && int(sig.Signer) < len(oracleIdentities)) { - return fmt.Errorf("signer out of bounds: %v", sig.Signer) - } - if err := sig.Signature.Verify( - ogid, - seqNr, - astb.StateTransitionBlock.StateTransitionInputsDigest, - MakeStateTransitionOutputDigest( - ogid, - seqNr, - astb.StateTransitionBlock.StateTransitionOutputs.WriteSet, - ), - astb.StateTransitionBlock.StateRootDigest, - MakeReportsPlusPrecursorDigest( - ogid, - seqNr, - astb.StateTransitionBlock.ReportsPlusPrecursor, - ), - oracleIdentities[sig.Signer].OffchainPublicKey, - ); err != nil { - return fmt.Errorf("%v-th signature by %v-th oracle with pubkey %x does not verify: %w", - i, sig.Signer, oracleIdentities[sig.Signer].OffchainPublicKey, err) - } - } - return nil + certifiedCommit := astb.ToCertifiedCommit(configDigest) + return certifiedCommit.Verify(configDigest, oracleIdentities, byzQuorumSize) } -type CertifiedCommittedReports[RI any] struct { - CommitEpoch uint64 - SeqNr uint64 - StateTransitionInputsDigest StateTransitionInputsDigest - StateTransitionOutputDigest StateTransitionOutputDigest - StateRootDigest StateRootDigest - ReportsPlusPrecursor ocr3_1types.ReportsPlusPrecursor - CommitQuorumCertificate []AttributedCommitSignature -} - -func (ccrs *CertifiedCommittedReports[RI]) isGenesis() bool { - return ccrs.CommitEpoch == uint64(0) && ccrs.SeqNr == uint64(0) && - ccrs.StateTransitionInputsDigest == StateTransitionInputsDigest{} && - ccrs.StateTransitionOutputDigest == StateTransitionOutputDigest{} && - len(ccrs.ReportsPlusPrecursor) == 0 && - len(ccrs.CommitQuorumCertificate) == 0 -} - -func (ccrs *CertifiedCommittedReports[RI]) CheckSize(n int, f int, limits ocr3_1types.ReportingPluginLimits, maxReportSigLen int) bool { - // Check if we this is a genesis certificate - if ccrs.isGenesis() { - return true - } - - if len(ccrs.ReportsPlusPrecursor) > limits.MaxReportsPlusPrecursorLength { - return false - } - - if len(ccrs.CommitQuorumCertificate) != byzquorum.Size(n, f) { - return false - } - for _, acs := range ccrs.CommitQuorumCertificate { - if len(acs.Signature) != ed25519.SignatureSize { - return false - } - } - return true -} - -func (ccrs *CertifiedCommittedReports[RI]) Verify( - configDigest types.ConfigDigest, - oracleIdentities []config.OracleIdentity, - byzQuorumSize int, -) error { - if byzQuorumSize != len(ccrs.CommitQuorumCertificate) { - return fmt.Errorf("wrong number of signatures, expected %d for byz. quorum but got %d", byzQuorumSize, len(ccrs.CommitQuorumCertificate)) - } - - ogid := OutcomeGenerationID{ +func (astb *AttestedStateTransitionBlock) ToCertifiedCommit(configDigest types.ConfigDigest) CertifiedCommit { + stb := astb.StateTransitionBlock + stateTransitionOutputsDigest := MakeStateTransitionOutputDigest( configDigest, - ccrs.CommitEpoch, + stb.SeqNr(), + stb.StateTransitionOutputs.WriteSet, + ) + return CertifiedCommit{ + stb.Epoch, + stb.SeqNr(), + stb.StateTransitionInputsDigest, + stateTransitionOutputsDigest, + stb.StateRootDigest, + stb.ReportsPlusPrecursorDigest, + astb.AttributedCommitSignatures, } - - seen := make(map[commontypes.OracleID]bool) - for i, acs := range ccrs.CommitQuorumCertificate { - if seen[acs.Signer] { - return fmt.Errorf("duplicate signature by %v", acs.Signer) - } - seen[acs.Signer] = true - if !(0 <= int(acs.Signer) && int(acs.Signer) < len(oracleIdentities)) { - return fmt.Errorf("signer out of bounds: %v", acs.Signer) - } - reportsPlusPrecursorDigest := MakeReportsPlusPrecursorDigest(ogid, ccrs.SeqNr, ccrs.ReportsPlusPrecursor) - if err := acs.Signature.Verify(ogid, - ccrs.SeqNr, - ccrs.StateTransitionInputsDigest, - ccrs.StateTransitionOutputDigest, - ccrs.StateRootDigest, - reportsPlusPrecursorDigest, - oracleIdentities[acs.Signer].OffchainPublicKey); err != nil { - return fmt.Errorf("%v-th signature by %v-th oracle does not verify: %w", i, acs.Signer, err) - } - } - return nil } type BlobDigest = blobtypes.BlobDigest type BlobChunkDigest = blobtypes.BlobChunkDigest +type BlobChunkDigestsRoot = blobtypes.BlobChunkDigestsRoot type BlobAvailabilitySignature = blobtypes.BlobAvailabilitySignature type AttributedBlobAvailabilitySignature = blobtypes.AttributedBlobAvailabilitySignature type LightCertifiedBlob = blobtypes.LightCertifiedBlob diff --git a/offchainreporting2plus/internal/ocr3_1/protocol/state_sync.go b/offchainreporting2plus/internal/ocr3_1/protocol/state_sync.go index ad99e471..3d67ee11 100644 --- a/offchainreporting2plus/internal/ocr3_1/protocol/state_sync.go +++ b/offchainreporting2plus/internal/ocr3_1/protocol/state_sync.go @@ -9,24 +9,19 @@ import ( "github.com/google/btree" "github.com/smartcontractkit/libocr/commontypes" "github.com/smartcontractkit/libocr/internal/loghelper" - "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3config" + "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config" "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/ocr3_1/protocol/requestergadget" "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3_1types" "github.com/smartcontractkit/libocr/subprocesses" ) -const ( - // An oracle sends a STATE-SYNC-SUMMARY message every DeltaStateSyncHeartbeat - DeltaStateSyncHeartbeat time.Duration = 1 * time.Second -) - func RunStateSync[RI any]( ctx context.Context, chNetToStateSync <-chan MessageToStateSyncWithSender[RI], chOutcomeGenerationToStateSync <-chan EventToStateSync[RI], chReportAttestationToStateSync <-chan EventToStateSync[RI], - config ocr3config.SharedConfig, + config ocr3_1config.SharedConfig, database Database, id commontypes.OracleID, kvDb KeyValueDatabase, @@ -75,7 +70,7 @@ type stateSyncState[RI any] struct { chNotificationToStateDestroyIfNeeded chan<- struct{} chOutcomeGenerationToStateSync <-chan EventToStateSync[RI] chReportAttestationToStateSync <-chan EventToStateSync[RI] - config ocr3config.SharedConfig + config ocr3_1config.SharedConfig database Database id commontypes.OracleID kvDb KeyValueDatabase @@ -225,7 +220,7 @@ func (stasy *stateSyncState[RI]) refreshStateSyncState() (ok bool) { func (stasy *stateSyncState[RI]) eventTSendSummaryTimeout() { defer func() { - stasy.tSendSummary = time.After(DeltaStateSyncHeartbeat) + stasy.tSendSummary = time.After(stasy.config.GetDeltaStateSyncSummaryInterval()) }() if !stasy.refreshStateSyncState() { return @@ -260,8 +255,9 @@ func (stasy *stateSyncState[RI]) messageStateSyncSummary(msg MessageStateSyncSum stasy.tryToKickStartSync() } +// max fresh summary age func (stasy *stateSyncState[RI]) summaryFreshnessCutoff() time.Duration { - return stasy.config.DeltaProgress / 4 + return 4 * stasy.config.GetDeltaStateSyncSummaryInterval() } type honestOraclePruneStatus int @@ -352,12 +348,12 @@ func (stasy *stateSyncState[RI]) decideBlockSyncOrTreeSyncBasedOnSummariesAndHig } func (stasy *stateSyncState[RI]) pickSomeTreeSyncTarget() (uint64, bool) { - if snapshotSeqNr(stasy.highestHeardSeqNr) == stasy.highestHeardSeqNr { + if snapshotSeqNr(stasy.highestHeardSeqNr, stasy.config.PublicConfig) == stasy.highestHeardSeqNr { return stasy.highestHeardSeqNr, true } else { - snapshotIndex := snapshotIndexFromSeqNr(stasy.highestHeardSeqNr) + snapshotIndex := snapshotIndexFromSeqNr(stasy.highestHeardSeqNr, stasy.config.PublicConfig) if snapshotIndex > 0 { - return maxSeqNrWithSnapshotIndex(snapshotIndex - 1), true + return maxSeqNrWithSnapshotIndex(snapshotIndex-1, stasy.config.PublicConfig), true } else { return 0, false } @@ -447,7 +443,7 @@ func newStateSyncState[RI any]( chNotificationToStateDestroyIfNeeded chan<- struct{}, chOutcomeGenerationToStateSync <-chan EventToStateSync[RI], chReportAttestationToStateSync <-chan EventToStateSync[RI], - config ocr3config.SharedConfig, + config ocr3_1config.SharedConfig, database Database, id commontypes.OracleID, kvDb KeyValueDatabase, @@ -500,19 +496,19 @@ func newStateSyncState[RI any]( PendingKeyDigestRanges{}, }, syncModeUnknown, - time.After(DeltaStateSyncHeartbeat), + time.After(config.GetDeltaStateSyncSummaryInterval()), } stasy.blockSyncState.blockRequesterGadget = requestergadget.NewRequesterGadget[seqNrRange]( config.N(), - DeltaMinBlockSyncRequest, + config.GetDeltaBlockSyncMinRequestToSameOracleInterval(), stasy.sendBlockSyncRequest, stasy.getPendingBlocksToRequest, stasy.getBlockSyncSeeders, ) stasy.treeSyncState.treeChunkRequesterGadget = requestergadget.NewRequesterGadget[treeSyncChunkRequestItem]( config.N(), - DeltaMinTreeSyncRequest, + config.GetDeltaTreeSyncMinRequestToSameOracleInterval(), stasy.sendTreeSyncChunkRequest, stasy.getPendingTreeSyncChunksToRequest, stasy.getTreeSyncChunkSeeders, diff --git a/offchainreporting2plus/internal/ocr3_1/protocol/state_sync_block.go b/offchainreporting2plus/internal/ocr3_1/protocol/state_sync_block.go index 8dca72fa..d5fa0cd5 100644 --- a/offchainreporting2plus/internal/ocr3_1/protocol/state_sync_block.go +++ b/offchainreporting2plus/internal/ocr3_1/protocol/state_sync_block.go @@ -6,20 +6,7 @@ import ( "github.com/google/btree" "github.com/smartcontractkit/libocr/commontypes" "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/ocr3_1/protocol/requestergadget" -) - -const ( - MaxBlocksPerBlockSyncResponse int = 10 - - // Minimum delay between two consecutive BLOCK-SYNC-REQ requests - DeltaMinBlockSyncRequest = 10 * time.Millisecond - // Maximum delay between a BLOCK-SYNC-REQ and a BLOCK-SYNC response. We'll try - // with another oracle if we don't get a response in this time. - DeltaMaxBlockSyncRequest time.Duration = 1 * time.Second - - // We are looking to pipeline fetches of a range of at most - // BlockSyncLookahead blocks at any given time - BlockSyncLookahead = 10_000 + "github.com/smartcontractkit/libocr/offchainreporting2plus/types" ) // Half-open range, i.e. [StartSeqNr, EndExclSeqNr) @@ -81,13 +68,15 @@ func (stasy *stateSyncState[RI]) getPendingBlocksToRequest() []seqNrRange { stasy.reapBlockBuffer() lastSeqNr := stasy.highestPersistedStateTransitionBlockSeqNr + cfgMaxBlocksPerBlockSyncResponse := uint64(stasy.config.GetMaxBlocksPerBlockSyncResponse()) + cfgBlockSyncLookahead := stasy.config.GetMaxParallelRequestedBlocks() stasy.blockSyncState.sortedBlockBuffer.Ascend(func(astb AttestedStateTransitionBlock) bool { seqNr := astb.StateTransitionBlock.SeqNr() if lastSeqNr+1 < seqNr { // [lastSeqNr+1..seqNr) (exclusive) is a gap to fill - for rangeStartSeqNr := lastSeqNr + 1; rangeStartSeqNr < seqNr; rangeStartSeqNr += uint64(MaxBlocksPerBlockSyncResponse) { - rangeEndExclSeqNr := rangeStartSeqNr + uint64(MaxBlocksPerBlockSyncResponse) + for rangeStartSeqNr := lastSeqNr + 1; rangeStartSeqNr < seqNr; rangeStartSeqNr += cfgMaxBlocksPerBlockSyncResponse { + rangeEndExclSeqNr := rangeStartSeqNr + cfgMaxBlocksPerBlockSyncResponse if rangeEndExclSeqNr > seqNr { rangeEndExclSeqNr = seqNr } @@ -98,10 +87,10 @@ func (stasy *stateSyncState[RI]) getPendingBlocksToRequest() []seqNrRange { return true }) - for rangeStartSeqNr := lastSeqNr + 1; rangeStartSeqNr <= stasy.highestPersistedStateTransitionBlockSeqNr+BlockSyncLookahead && rangeStartSeqNr <= stasy.highestHeardSeqNr; rangeStartSeqNr += uint64(MaxBlocksPerBlockSyncResponse) { - rangeEndExclSeqNr := rangeStartSeqNr + uint64(MaxBlocksPerBlockSyncResponse) - if rangeEndExclSeqNr > stasy.highestPersistedStateTransitionBlockSeqNr+BlockSyncLookahead { - rangeEndExclSeqNr = stasy.highestPersistedStateTransitionBlockSeqNr + BlockSyncLookahead + for rangeStartSeqNr := lastSeqNr + 1; rangeStartSeqNr <= stasy.highestPersistedStateTransitionBlockSeqNr+cfgBlockSyncLookahead && rangeStartSeqNr <= stasy.highestHeardSeqNr; rangeStartSeqNr += cfgMaxBlocksPerBlockSyncResponse { + rangeEndExclSeqNr := rangeStartSeqNr + cfgMaxBlocksPerBlockSyncResponse + if rangeEndExclSeqNr > stasy.highestPersistedStateTransitionBlockSeqNr+cfgBlockSyncLookahead { + rangeEndExclSeqNr = stasy.highestPersistedStateTransitionBlockSeqNr + cfgBlockSyncLookahead } // no check for rangeEndExclSeqNr > stasy.highestHeardSeqNr, because there is no harm in asking for more than exists pending = append(pending, seqNrRange{rangeStartSeqNr, rangeEndExclSeqNr}) @@ -127,15 +116,18 @@ func (stasy *stateSyncState[RI]) sendBlockSyncRequest(seqNrRange seqNrRange, tar "seqNrRange": seqNrRange, "target": target, }) + + requestInfo := &types.RequestInfo{ + time.Now().Add(stasy.config.GetDeltaBlockSyncResponseTimeout()), + } msg := MessageBlockSyncRequest[RI]{ - nil, // TODO: consider using a sentinel value here, e.g. "EmptyRequestHandleForInboundResponse" + types.EmptyRequestHandleForOutboundRequest, + requestInfo, seqNrRange.StartSeqNr, seqNrRange.EndExclSeqNr, } stasy.netSender.SendTo(msg, target) - return &requestergadget.RequestInfo{ - time.Now().Add(DeltaMaxBlockSyncRequest), - }, true + return requestInfo, true } func (stasy *stateSyncState[RI]) messageBlockSyncRequest(msg MessageBlockSyncRequest[RI], sender commontypes.OracleID) { @@ -156,9 +148,10 @@ func (stasy *stateSyncState[RI]) messageBlockSyncRequest(msg MessageBlockSyncReq var maxBlocksInResponse int { + cfgMaxBlocksPerBlockSyncResponse := uint64(stasy.config.GetMaxBlocksPerBlockSyncResponse()) maxBlocksInResponseU64 := msg.EndExclSeqNr - msg.StartSeqNr - if maxBlocksInResponseU64 > uint64(MaxBlocksPerBlockSyncResponse) { - maxBlocksInResponseU64 = uint64(MaxBlocksPerBlockSyncResponse) + if maxBlocksInResponseU64 > cfgMaxBlocksPerBlockSyncResponse { + maxBlocksInResponseU64 = cfgMaxBlocksPerBlockSyncResponse } // now we are sure that maxBlocksInResponseU64 will fit an int maxBlocksInResponse = int(maxBlocksInResponseU64) diff --git a/offchainreporting2plus/internal/ocr3_1/protocol/state_sync_reap.go b/offchainreporting2plus/internal/ocr3_1/protocol/state_sync_reap.go index 9dbb63b2..b849bc33 100644 --- a/offchainreporting2plus/internal/ocr3_1/protocol/state_sync_reap.go +++ b/offchainreporting2plus/internal/ocr3_1/protocol/state_sync_reap.go @@ -7,7 +7,7 @@ import ( "github.com/smartcontractkit/libocr/commontypes" "github.com/smartcontractkit/libocr/internal/loghelper" - "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3config" + "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config" ) const ( @@ -19,7 +19,7 @@ const ( maxTreeRootsToReapInOneGo = 100_000 ) -func reapState(ctx context.Context, kvDb KeyValueDatabase, logger commontypes.Logger) (done bool, err error) { +func reapState(ctx context.Context, kvDb KeyValueDatabase, logger commontypes.Logger, config ocr3_1config.PublicConfig) (done bool, err error) { tx, err := kvDb.NewUnserializedReadWriteTransactionUnchecked() if err != nil { @@ -44,7 +44,7 @@ func reapState(ctx context.Context, kvDb KeyValueDatabase, logger commontypes.Lo return false, fmt.Errorf("failed to read lowest persisted seq nr: %w", err) } - desiredLowestPersistedSeqNr := desiredLowestPersistedSeqNr(highestCommittedSeqNr) + desiredLowestPersistedSeqNr := desiredLowestPersistedSeqNr(highestCommittedSeqNr, config) if desiredLowestPersistedSeqNr > lowestPersistedSeqNr { logger.Info("RunStateSyncReap: new lowest persisted seq nr", commontypes.LogFields{ "desiredLowestPersistedSeqNr": desiredLowestPersistedSeqNr, @@ -89,7 +89,7 @@ func reapState(ctx context.Context, kvDb KeyValueDatabase, logger commontypes.Lo }) for { - done, err := reapTreeNodes(kvDb, desiredLowestPersistedSeqNr) + done, err := reapTreeNodes(kvDb, desiredLowestPersistedSeqNr, config) if err != nil { return false, fmt.Errorf("failed to reap tree nodes: %w", err) } @@ -106,7 +106,7 @@ func reapState(ctx context.Context, kvDb KeyValueDatabase, logger commontypes.Lo }) for { - done, err := reapTreeRoots(kvDb, desiredLowestPersistedSeqNr) + done, err := reapTreeRoots(kvDb, desiredLowestPersistedSeqNr, config) if err != nil { return false, fmt.Errorf("failed to reap tree roots: %w", err) } @@ -144,14 +144,14 @@ func reapBlocks(kvDb KeyValueDatabase, desiredLowestPersistedSeqNr uint64) (done return done, nil } -func reapTreeNodes(kvDb KeyValueDatabase, desiredLowestPersistedSeqNr uint64) (done bool, err error) { +func reapTreeNodes(kvDb KeyValueDatabase, desiredLowestPersistedSeqNr uint64, config ocr3_1config.PublicConfig) (done bool, err error) { tx, err := kvDb.NewUnserializedReadWriteTransactionUnchecked() if err != nil { return false, fmt.Errorf("failed to create read/write transaction: %w", err) } defer tx.Discard() - done, err = tx.DeleteStaleNodes(RootVersion(desiredLowestPersistedSeqNr), maxTreeNodesToReapInOneGo) + done, err = tx.DeleteStaleNodes(RootVersion(desiredLowestPersistedSeqNr, config), maxTreeNodesToReapInOneGo) if err != nil { return false, fmt.Errorf("failed to delete stale nodes: %w", err) } @@ -163,14 +163,14 @@ func reapTreeNodes(kvDb KeyValueDatabase, desiredLowestPersistedSeqNr uint64) (d return done, nil } -func reapTreeRoots(kvDb KeyValueDatabase, desiredLowestPersistedSeqNr uint64) (done bool, err error) { +func reapTreeRoots(kvDb KeyValueDatabase, desiredLowestPersistedSeqNr uint64, config ocr3_1config.PublicConfig) (done bool, err error) { tx, err := kvDb.NewUnserializedReadWriteTransactionUnchecked() if err != nil { return false, fmt.Errorf("failed to create read/write transaction: %w", err) } defer tx.Discard() - done, err = tx.DeleteRoots(RootVersion(desiredLowestPersistedSeqNr), maxTreeRootsToReapInOneGo) + done, err = tx.DeleteRoots(RootVersion(desiredLowestPersistedSeqNr, config), maxTreeRootsToReapInOneGo) if err != nil { return false, fmt.Errorf("failed to delete roots: %w", err) } @@ -184,7 +184,7 @@ func reapTreeRoots(kvDb KeyValueDatabase, desiredLowestPersistedSeqNr uint64) (d func RunStateSyncReap( ctx context.Context, - config ocr3config.SharedConfig, + config ocr3_1config.SharedConfig, logger loghelper.LoggerWithContext, database Database, kvDb KeyValueDatabase, @@ -200,7 +200,7 @@ func RunStateSyncReap( } logger.Info("RunStateSyncReap: calling reapState", nil) - done, err := reapState(ctx, kvDb, logger) + done, err := reapState(ctx, kvDb, logger, config.PublicConfig) if err != nil { logger.Warn("RunStateSyncReap: failed to reap state. Will retry soon.", commontypes.LogFields{ "error": err, diff --git a/offchainreporting2plus/internal/ocr3_1/protocol/state_sync_snapshot.go b/offchainreporting2plus/internal/ocr3_1/protocol/state_sync_snapshot.go index d8b6da64..b6cb799c 100644 --- a/offchainreporting2plus/internal/ocr3_1/protocol/state_sync_snapshot.go +++ b/offchainreporting2plus/internal/ocr3_1/protocol/state_sync_snapshot.go @@ -1,52 +1,47 @@ package protocol -const ( - SnapshotInterval = 128 - // MaxHistoricalSnapshotsRetained must be a non-zero value, denoting the - // number of complete snapshots prior to the current (potentially - // incomplete) one that will be retained to help other oracles with state - // sync. All blocks starting from the highest block of the earliest retained - // snapshot will be retained. - MaxHistoricalSnapshotsRetained = 64 +import ( + "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config" ) -func snapshotIndexFromSeqNr(seqNr uint64) uint64 { +func snapshotIndexFromSeqNr(seqNr uint64, config ocr3_1config.PublicConfig) uint64 { if seqNr == 0 { return 0 } - return (seqNr + SnapshotInterval - 1) / SnapshotInterval + return (seqNr + config.GetSnapshotInterval() - 1) / config.GetSnapshotInterval() } -func maxSeqNrWithSnapshotIndex(snapshotIndex uint64) uint64 { +func maxSeqNrWithSnapshotIndex(snapshotIndex uint64, config ocr3_1config.PublicConfig) uint64 { if snapshotIndex == 0 { return 0 } - return snapshotIndex * SnapshotInterval + return snapshotIndex * config.GetSnapshotInterval() } -func desiredLowestPersistedSeqNr(highestCommittedSeqNr uint64) uint64 { - highestSnapshotIndex := snapshotIndexFromSeqNr(highestCommittedSeqNr) +func desiredLowestPersistedSeqNr(highestCommittedSeqNr uint64, config ocr3_1config.PublicConfig) uint64 { + highestSnapshotIndex := snapshotIndexFromSeqNr(highestCommittedSeqNr, config) var lowestDesiredSnapshotIndex uint64 - if highestSnapshotIndex > MaxHistoricalSnapshotsRetained { - lowestDesiredSnapshotIndex = highestSnapshotIndex - MaxHistoricalSnapshotsRetained + cfgMaxHistoricalSnapshotsRetained := config.GetMaxHistoricalSnapshotsRetained() + if highestSnapshotIndex > cfgMaxHistoricalSnapshotsRetained { + lowestDesiredSnapshotIndex = highestSnapshotIndex - cfgMaxHistoricalSnapshotsRetained } else { lowestDesiredSnapshotIndex = 0 } - return maxSeqNrWithSnapshotIndex(lowestDesiredSnapshotIndex) + return maxSeqNrWithSnapshotIndex(lowestDesiredSnapshotIndex, config) } -func snapshotSeqNr(seqNr uint64) uint64 { - return maxSeqNrWithSnapshotIndex(snapshotIndexFromSeqNr(seqNr)) +func snapshotSeqNr(seqNr uint64, config ocr3_1config.PublicConfig) uint64 { + return maxSeqNrWithSnapshotIndex(snapshotIndexFromSeqNr(seqNr, config), config) } // prevRootVersion returns the version number of the JMT root referring to the // state as of seqNr - 1. This is used as the "old version" for writing the // modifications of seqNr. We only maintain trees with versions that are // multiples of SnapshotInterval. -func PrevRootVersion(seqNr uint64) uint64 { - return snapshotSeqNr(seqNr - 1) +func PrevRootVersion(seqNr uint64, config ocr3_1config.PublicConfig) uint64 { + return snapshotSeqNr(seqNr-1, config) } -func RootVersion(seqNr uint64) uint64 { - return snapshotSeqNr(seqNr) +func RootVersion(seqNr uint64, config ocr3_1config.PublicConfig) uint64 { + return snapshotSeqNr(seqNr, config) } diff --git a/offchainreporting2plus/internal/ocr3_1/protocol/state_sync_tree.go b/offchainreporting2plus/internal/ocr3_1/protocol/state_sync_tree.go index daae7254..c52f8dc7 100644 --- a/offchainreporting2plus/internal/ocr3_1/protocol/state_sync_tree.go +++ b/offchainreporting2plus/internal/ocr3_1/protocol/state_sync_tree.go @@ -7,28 +7,13 @@ import ( "github.com/smartcontractkit/libocr/commontypes" "github.com/smartcontractkit/libocr/internal/jmt" + "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config" "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/ocr3_1/protocol/requestergadget" - "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3_1types" -) - -const ( - // Maximum delay between a TREE-SYNC-REQ and TREE-SYNC-CHUNK response. We'll try - // with another oracle if we don't get a response in this time. - DeltaMaxTreeSyncRequest time.Duration = 1 * time.Second - // Minimum delay between two consecutive BLOCK-SYNC-REQ requests - DeltaMinTreeSyncRequest = 10 * time.Millisecond - - // The maximum number of key-value pairs that an oracle will send in a single tree-sync chunk - MaxTreeSyncChunkKeys = 128 - // Maximum number of bytes in of the combined keys and values length in a chunk. - - MaxTreeSyncChunkKeysPlusValuesLength = 2 * (ocr3_1types.MaxMaxKeyValueKeyLength + ocr3_1types.MaxMaxKeyValueValueLength) - - MaxMaxParallelTreeSyncChunkFetches = 8 + "github.com/smartcontractkit/libocr/offchainreporting2plus/types" ) func (stasy *stateSyncState[RI]) maxParallelTreeSyncChunkFetches() int { - return max(1, min(MaxMaxParallelTreeSyncChunkFetches, stasy.config.N()-1)) + return max(1, min(stasy.config.GetMaxParallelTreeSyncChunkFetches(), stasy.config.N()-1)) } func (stasy *stateSyncState[RI]) newPendingKeyDigestRanges() PendingKeyDigestRanges { @@ -69,16 +54,19 @@ func (stasy *stateSyncState[RI]) sendTreeSyncChunkRequest(item treeSyncChunkRequ "keyDigestRange": item.keyDigestRange, "target": target, }) + + requestInfo := &types.RequestInfo{ + ExpiryTimestamp: time.Now().Add(stasy.config.GetDeltaTreeSyncResponseTimeout()), + } msg := MessageTreeSyncChunkRequest[RI]{ - nil, + types.EmptyRequestHandleForOutboundRequest, + requestInfo, item.targetSeqNr, item.keyDigestRange.StartIndex, item.keyDigestRange.EndInclIndex, } stasy.netSender.SendTo(msg, target) - return &requestergadget.RequestInfo{ - time.Now().Add(DeltaMaxTreeSyncRequest), - }, true + return requestInfo, true } func (stasy *stateSyncState[RI]) getPendingTreeSyncChunksToRequest() []treeSyncChunkRequestItem { @@ -277,7 +265,7 @@ func (stasy *stateSyncState[RI]) messageTreeSyncChunkRequest(msg MessageTreeSync "startIndex": msg.StartIndex, }) - if !mustTakeSnapshot(msg.ToSeqNr) { + if !mustTakeSnapshot(msg.ToSeqNr, stasy.config.PublicConfig) { stasy.treeSyncState.logger.Warn("dropping MessageTreeSyncChunkRequest with invalid SeqNr", commontypes.LogFields{ "toSeqNr": msg.ToSeqNr, }) @@ -584,6 +572,6 @@ func (stasy *stateSyncState[RI]) messageTreeSyncChunkResponse(msg MessageTreeSyn panic("unreachable") } -func mustTakeSnapshot(seqNr uint64) bool { - return seqNr%SnapshotInterval == 0 +func mustTakeSnapshot(seqNr uint64, config ocr3_1config.PublicConfig) bool { + return seqNr%config.GetSnapshotInterval() == 0 } diff --git a/offchainreporting2plus/internal/ocr3_1/protocol/transmission.go b/offchainreporting2plus/internal/ocr3_1/protocol/transmission.go index ac662435..068e3bd5 100644 --- a/offchainreporting2plus/internal/ocr3_1/protocol/transmission.go +++ b/offchainreporting2plus/internal/ocr3_1/protocol/transmission.go @@ -5,14 +5,15 @@ import ( "crypto/hmac" "crypto/sha256" "encoding/binary" - "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/common" "slices" "time" + "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/common" + "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config" + "github.com/smartcontractkit/libocr/commontypes" "github.com/smartcontractkit/libocr/internal/loghelper" "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/common/scheduler" - "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3config" "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3_1types" "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3types" "github.com/smartcontractkit/libocr/offchainreporting2plus/types" @@ -26,7 +27,7 @@ func RunTransmission[RI any]( ctx context.Context, chReportAttestationToTransmission <-chan EventToTransmission[RI], - config ocr3config.SharedConfig, + config ocr3_1config.SharedConfig, contractTransmitter ocr3types.ContractTransmitter[RI], id commontypes.OracleID, localConfig types.LocalConfig, @@ -58,7 +59,7 @@ type transmissionState[RI any] struct { subs subprocesses.Subprocesses chReportAttestationToTransmission <-chan EventToTransmission[RI] - config ocr3config.SharedConfig + config ocr3_1config.SharedConfig contractTransmitter ocr3types.ContractTransmitter[RI] id commontypes.OracleID localConfig types.LocalConfig diff --git a/offchainreporting2plus/internal/ocr3_1/serialization/offchainreporting3_1_db.pb.go b/offchainreporting2plus/internal/ocr3_1/serialization/offchainreporting3_1_db.pb.go index c470175f..747c2a51 100644 --- a/offchainreporting2plus/internal/ocr3_1/serialization/offchainreporting3_1_db.pb.go +++ b/offchainreporting2plus/internal/ocr3_1/serialization/offchainreporting3_1_db.pb.go @@ -257,9 +257,11 @@ type BlobMeta struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - PayloadLength uint64 `protobuf:"varint,1,opt,name=payload_length,json=payloadLength,proto3" json:"payload_length,omitempty"` - ChunkHaves []bool `protobuf:"varint,2,rep,packed,name=chunk_haves,json=chunkHaves,proto3" json:"chunk_haves,omitempty"` - ExpirySeqNr uint64 `protobuf:"varint,3,opt,name=expiry_seq_nr,json=expirySeqNr,proto3" json:"expiry_seq_nr,omitempty"` + PayloadLength uint64 `protobuf:"varint,1,opt,name=payload_length,json=payloadLength,proto3" json:"payload_length,omitempty"` + ChunkHaves []bool `protobuf:"varint,2,rep,packed,name=chunk_haves,json=chunkHaves,proto3" json:"chunk_haves,omitempty"` + ChunkDigests [][]byte `protobuf:"bytes,3,rep,name=chunk_digests,json=chunkDigests,proto3" json:"chunk_digests,omitempty"` + ExpirySeqNr uint64 `protobuf:"varint,4,opt,name=expiry_seq_nr,json=expirySeqNr,proto3" json:"expiry_seq_nr,omitempty"` + Submitter uint32 `protobuf:"varint,5,opt,name=submitter,proto3" json:"submitter,omitempty"` } func (x *BlobMeta) Reset() { @@ -308,6 +310,13 @@ func (x *BlobMeta) GetChunkHaves() []bool { return nil } +func (x *BlobMeta) GetChunkDigests() [][]byte { + if x != nil { + return x.ChunkDigests + } + return nil +} + func (x *BlobMeta) GetExpirySeqNr() uint64 { if x != nil { return x.ExpirySeqNr @@ -315,6 +324,68 @@ func (x *BlobMeta) GetExpirySeqNr() uint64 { return 0 } +func (x *BlobMeta) GetSubmitter() uint32 { + if x != nil { + return x.Submitter + } + return 0 +} + +type BlobQuotaStats struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Count uint64 `protobuf:"varint,1,opt,name=count,proto3" json:"count,omitempty"` + CumulativePayloadLength uint64 `protobuf:"varint,2,opt,name=cumulative_payload_length,json=cumulativePayloadLength,proto3" json:"cumulative_payload_length,omitempty"` +} + +func (x *BlobQuotaStats) Reset() { + *x = BlobQuotaStats{} + if protoimpl.UnsafeEnabled { + mi := &file_offchainreporting3_1_db_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BlobQuotaStats) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BlobQuotaStats) ProtoMessage() {} + +func (x *BlobQuotaStats) ProtoReflect() protoreflect.Message { + mi := &file_offchainreporting3_1_db_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BlobQuotaStats.ProtoReflect.Descriptor instead. +func (*BlobQuotaStats) Descriptor() ([]byte, []int) { + return file_offchainreporting3_1_db_proto_rawDescGZIP(), []int{4} +} + +func (x *BlobQuotaStats) GetCount() uint64 { + if x != nil { + return x.Count + } + return 0 +} + +func (x *BlobQuotaStats) GetCumulativePayloadLength() uint64 { + if x != nil { + return x.CumulativePayloadLength + } + return 0 +} + var File_offchainreporting3_1_db_proto protoreflect.FileDescriptor var file_offchainreporting3_1_db_proto_rawDesc = []byte{ @@ -350,22 +421,33 @@ var file_offchainreporting3_1_db_proto_rawDesc = []byte{ 0x6e, 0x74, 0x5f, 0x6e, 0x65, 0x77, 0x5f, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x5f, 0x77, 0x69, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x17, 0x68, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x53, 0x65, 0x6e, 0x74, 0x4e, 0x65, 0x77, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x57, 0x69, 0x73, 0x68, - 0x22, 0x76, 0x0a, 0x08, 0x42, 0x6c, 0x6f, 0x62, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x25, 0x0a, 0x0e, - 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x4c, 0x65, 0x6e, - 0x67, 0x74, 0x68, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x5f, 0x68, 0x61, 0x76, - 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x08, 0x52, 0x0a, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x48, - 0x61, 0x76, 0x65, 0x73, 0x12, 0x22, 0x0a, 0x0d, 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, 0x5f, 0x73, - 0x65, 0x71, 0x5f, 0x6e, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x65, 0x78, 0x70, - 0x69, 0x72, 0x79, 0x53, 0x65, 0x71, 0x4e, 0x72, 0x2a, 0x66, 0x0a, 0x0d, 0x54, 0x72, 0x65, 0x65, - 0x53, 0x79, 0x6e, 0x63, 0x50, 0x68, 0x61, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x18, 0x54, 0x52, 0x45, - 0x45, 0x5f, 0x53, 0x59, 0x4e, 0x43, 0x5f, 0x50, 0x48, 0x41, 0x53, 0x45, 0x5f, 0x49, 0x4e, 0x41, - 0x43, 0x54, 0x49, 0x56, 0x45, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x54, 0x52, 0x45, 0x45, 0x5f, - 0x53, 0x59, 0x4e, 0x43, 0x5f, 0x50, 0x48, 0x41, 0x53, 0x45, 0x5f, 0x57, 0x41, 0x49, 0x54, 0x49, - 0x4e, 0x47, 0x10, 0x01, 0x12, 0x1a, 0x0a, 0x16, 0x54, 0x52, 0x45, 0x45, 0x5f, 0x53, 0x59, 0x4e, - 0x43, 0x5f, 0x50, 0x48, 0x41, 0x53, 0x45, 0x5f, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x10, 0x02, - 0x42, 0x11, 0x5a, 0x0f, 0x2e, 0x3b, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x22, 0xb9, 0x01, 0x0a, 0x08, 0x42, 0x6c, 0x6f, 0x62, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x25, 0x0a, + 0x0e, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x4c, 0x65, + 0x6e, 0x67, 0x74, 0x68, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x5f, 0x68, 0x61, + 0x76, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x08, 0x52, 0x0a, 0x63, 0x68, 0x75, 0x6e, 0x6b, + 0x48, 0x61, 0x76, 0x65, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x5f, 0x64, + 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0c, 0x63, 0x68, + 0x75, 0x6e, 0x6b, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x12, 0x22, 0x0a, 0x0d, 0x65, 0x78, + 0x70, 0x69, 0x72, 0x79, 0x5f, 0x73, 0x65, 0x71, 0x5f, 0x6e, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x0b, 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, 0x53, 0x65, 0x71, 0x4e, 0x72, 0x12, 0x1c, + 0x0a, 0x09, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x09, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x72, 0x22, 0x62, 0x0a, 0x0e, + 0x42, 0x6c, 0x6f, 0x62, 0x51, 0x75, 0x6f, 0x74, 0x61, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x14, + 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x3a, 0x0a, 0x19, 0x63, 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x69, + 0x76, 0x65, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x6c, 0x65, 0x6e, 0x67, 0x74, + 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x17, 0x63, 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, + 0x69, 0x76, 0x65, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, + 0x2a, 0x66, 0x0a, 0x0d, 0x54, 0x72, 0x65, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x50, 0x68, 0x61, 0x73, + 0x65, 0x12, 0x1c, 0x0a, 0x18, 0x54, 0x52, 0x45, 0x45, 0x5f, 0x53, 0x59, 0x4e, 0x43, 0x5f, 0x50, + 0x48, 0x41, 0x53, 0x45, 0x5f, 0x49, 0x4e, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x10, 0x00, 0x12, + 0x1b, 0x0a, 0x17, 0x54, 0x52, 0x45, 0x45, 0x5f, 0x53, 0x59, 0x4e, 0x43, 0x5f, 0x50, 0x48, 0x41, + 0x53, 0x45, 0x5f, 0x57, 0x41, 0x49, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x1a, 0x0a, 0x16, + 0x54, 0x52, 0x45, 0x45, 0x5f, 0x53, 0x59, 0x4e, 0x43, 0x5f, 0x50, 0x48, 0x41, 0x53, 0x45, 0x5f, + 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x10, 0x02, 0x42, 0x11, 0x5a, 0x0f, 0x2e, 0x3b, 0x73, 0x65, + 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, } var ( @@ -381,13 +463,14 @@ func file_offchainreporting3_1_db_proto_rawDescGZIP() []byte { } var file_offchainreporting3_1_db_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_offchainreporting3_1_db_proto_msgTypes = make([]protoimpl.MessageInfo, 4) +var file_offchainreporting3_1_db_proto_msgTypes = make([]protoimpl.MessageInfo, 5) var file_offchainreporting3_1_db_proto_goTypes = []interface{}{ (TreeSyncPhase)(0), // 0: offchainreporting3_1.TreeSyncPhase (*KeyDigestRange)(nil), // 1: offchainreporting3_1.KeyDigestRange (*TreeSyncStatus)(nil), // 2: offchainreporting3_1.TreeSyncStatus (*PacemakerState)(nil), // 3: offchainreporting3_1.PacemakerState (*BlobMeta)(nil), // 4: offchainreporting3_1.BlobMeta + (*BlobQuotaStats)(nil), // 5: offchainreporting3_1.BlobQuotaStats } var file_offchainreporting3_1_db_proto_depIdxs = []int32{ 0, // 0: offchainreporting3_1.TreeSyncStatus.phase:type_name -> offchainreporting3_1.TreeSyncPhase @@ -453,6 +536,18 @@ func file_offchainreporting3_1_db_proto_init() { return nil } } + file_offchainreporting3_1_db_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*BlobQuotaStats); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -460,7 +555,7 @@ func file_offchainreporting3_1_db_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_offchainreporting3_1_db_proto_rawDesc, NumEnums: 1, - NumMessages: 4, + NumMessages: 5, NumExtensions: 0, NumServices: 0, }, diff --git a/offchainreporting2plus/internal/ocr3_1/serialization/offchainreporting3_1_messages.pb.go b/offchainreporting2plus/internal/ocr3_1/serialization/offchainreporting3_1_messages.pb.go index 60238629..9dcaf042 100644 --- a/offchainreporting2plus/internal/ocr3_1/serialization/offchainreporting3_1_messages.pb.go +++ b/offchainreporting2plus/internal/ocr3_1/serialization/offchainreporting3_1_messages.pb.go @@ -36,8 +36,8 @@ type MessageWrapper struct { // *MessageWrapper_MessagePrepare // *MessageWrapper_MessageCommit // *MessageWrapper_MessageReportSignatures - // *MessageWrapper_MessageCertifiedCommitRequest - // *MessageWrapper_MessageCertifiedCommit + // *MessageWrapper_MessageReportsPlusPrecursorRequest + // *MessageWrapper_MessageReportsPlusPrecursor // *MessageWrapper_MessageBlockSyncRequest // *MessageWrapper_MessageBlockSyncResponse // *MessageWrapper_MessageStateSyncSummary @@ -152,16 +152,16 @@ func (x *MessageWrapper) GetMessageReportSignatures() *MessageReportSignatures { return nil } -func (x *MessageWrapper) GetMessageCertifiedCommitRequest() *MessageCertifiedCommitRequest { - if x, ok := x.GetMsg().(*MessageWrapper_MessageCertifiedCommitRequest); ok { - return x.MessageCertifiedCommitRequest +func (x *MessageWrapper) GetMessageReportsPlusPrecursorRequest() *MessageReportsPlusPrecursorRequest { + if x, ok := x.GetMsg().(*MessageWrapper_MessageReportsPlusPrecursorRequest); ok { + return x.MessageReportsPlusPrecursorRequest } return nil } -func (x *MessageWrapper) GetMessageCertifiedCommit() *MessageCertifiedCommit { - if x, ok := x.GetMsg().(*MessageWrapper_MessageCertifiedCommit); ok { - return x.MessageCertifiedCommit +func (x *MessageWrapper) GetMessageReportsPlusPrecursor() *MessageReportsPlusPrecursor { + if x, ok := x.GetMsg().(*MessageWrapper_MessageReportsPlusPrecursor); ok { + return x.MessageReportsPlusPrecursor } return nil } @@ -234,83 +234,83 @@ type isMessageWrapper_Msg interface { } type MessageWrapper_MessageNewEpochWish struct { - MessageNewEpochWish *MessageNewEpochWish `protobuf:"bytes,17,opt,name=message_new_epoch_wish,json=messageNewEpochWish,proto3,oneof"` + MessageNewEpochWish *MessageNewEpochWish `protobuf:"bytes,35,opt,name=message_new_epoch_wish,json=messageNewEpochWish,proto3,oneof"` } type MessageWrapper_MessageEpochStartRequest struct { - MessageEpochStartRequest *MessageEpochStartRequest `protobuf:"bytes,18,opt,name=message_epoch_start_request,json=messageEpochStartRequest,proto3,oneof"` + MessageEpochStartRequest *MessageEpochStartRequest `protobuf:"bytes,36,opt,name=message_epoch_start_request,json=messageEpochStartRequest,proto3,oneof"` } type MessageWrapper_MessageEpochStart struct { - MessageEpochStart *MessageEpochStart `protobuf:"bytes,19,opt,name=message_epoch_start,json=messageEpochStart,proto3,oneof"` + MessageEpochStart *MessageEpochStart `protobuf:"bytes,37,opt,name=message_epoch_start,json=messageEpochStart,proto3,oneof"` } type MessageWrapper_MessageRoundStart struct { - MessageRoundStart *MessageRoundStart `protobuf:"bytes,20,opt,name=message_round_start,json=messageRoundStart,proto3,oneof"` + MessageRoundStart *MessageRoundStart `protobuf:"bytes,38,opt,name=message_round_start,json=messageRoundStart,proto3,oneof"` } type MessageWrapper_MessageObservation struct { - MessageObservation *MessageObservation `protobuf:"bytes,21,opt,name=message_observation,json=messageObservation,proto3,oneof"` + MessageObservation *MessageObservation `protobuf:"bytes,39,opt,name=message_observation,json=messageObservation,proto3,oneof"` } type MessageWrapper_MessageProposal struct { - MessageProposal *MessageProposal `protobuf:"bytes,22,opt,name=message_proposal,json=messageProposal,proto3,oneof"` + MessageProposal *MessageProposal `protobuf:"bytes,40,opt,name=message_proposal,json=messageProposal,proto3,oneof"` } type MessageWrapper_MessagePrepare struct { - MessagePrepare *MessagePrepare `protobuf:"bytes,23,opt,name=message_prepare,json=messagePrepare,proto3,oneof"` + MessagePrepare *MessagePrepare `protobuf:"bytes,41,opt,name=message_prepare,json=messagePrepare,proto3,oneof"` } type MessageWrapper_MessageCommit struct { - MessageCommit *MessageCommit `protobuf:"bytes,24,opt,name=message_commit,json=messageCommit,proto3,oneof"` + MessageCommit *MessageCommit `protobuf:"bytes,42,opt,name=message_commit,json=messageCommit,proto3,oneof"` } type MessageWrapper_MessageReportSignatures struct { - MessageReportSignatures *MessageReportSignatures `protobuf:"bytes,25,opt,name=message_report_signatures,json=messageReportSignatures,proto3,oneof"` + MessageReportSignatures *MessageReportSignatures `protobuf:"bytes,43,opt,name=message_report_signatures,json=messageReportSignatures,proto3,oneof"` } -type MessageWrapper_MessageCertifiedCommitRequest struct { - MessageCertifiedCommitRequest *MessageCertifiedCommitRequest `protobuf:"bytes,26,opt,name=message_certified_commit_request,json=messageCertifiedCommitRequest,proto3,oneof"` +type MessageWrapper_MessageReportsPlusPrecursorRequest struct { + MessageReportsPlusPrecursorRequest *MessageReportsPlusPrecursorRequest `protobuf:"bytes,44,opt,name=message_reports_plus_precursor_request,json=messageReportsPlusPrecursorRequest,proto3,oneof"` } -type MessageWrapper_MessageCertifiedCommit struct { - MessageCertifiedCommit *MessageCertifiedCommit `protobuf:"bytes,27,opt,name=message_certified_commit,json=messageCertifiedCommit,proto3,oneof"` +type MessageWrapper_MessageReportsPlusPrecursor struct { + MessageReportsPlusPrecursor *MessageReportsPlusPrecursor `protobuf:"bytes,45,opt,name=message_reports_plus_precursor,json=messageReportsPlusPrecursor,proto3,oneof"` } type MessageWrapper_MessageBlockSyncRequest struct { - MessageBlockSyncRequest *MessageBlockSyncRequest `protobuf:"bytes,28,opt,name=message_block_sync_request,json=messageBlockSyncRequest,proto3,oneof"` + MessageBlockSyncRequest *MessageBlockSyncRequest `protobuf:"bytes,46,opt,name=message_block_sync_request,json=messageBlockSyncRequest,proto3,oneof"` } type MessageWrapper_MessageBlockSyncResponse struct { - MessageBlockSyncResponse *MessageBlockSyncResponse `protobuf:"bytes,29,opt,name=message_block_sync_response,json=messageBlockSyncResponse,proto3,oneof"` + MessageBlockSyncResponse *MessageBlockSyncResponse `protobuf:"bytes,47,opt,name=message_block_sync_response,json=messageBlockSyncResponse,proto3,oneof"` } type MessageWrapper_MessageStateSyncSummary struct { - MessageStateSyncSummary *MessageStateSyncSummary `protobuf:"bytes,30,opt,name=message_state_sync_summary,json=messageStateSyncSummary,proto3,oneof"` + MessageStateSyncSummary *MessageStateSyncSummary `protobuf:"bytes,48,opt,name=message_state_sync_summary,json=messageStateSyncSummary,proto3,oneof"` } type MessageWrapper_MessageTreeSyncChunkRequest struct { - MessageTreeSyncChunkRequest *MessageTreeSyncChunkRequest `protobuf:"bytes,31,opt,name=message_tree_sync_chunk_request,json=messageTreeSyncChunkRequest,proto3,oneof"` + MessageTreeSyncChunkRequest *MessageTreeSyncChunkRequest `protobuf:"bytes,49,opt,name=message_tree_sync_chunk_request,json=messageTreeSyncChunkRequest,proto3,oneof"` } type MessageWrapper_MessageTreeSyncChunkResponse struct { - MessageTreeSyncChunkResponse *MessageTreeSyncChunkResponse `protobuf:"bytes,32,opt,name=message_tree_sync_chunk_response,json=messageTreeSyncChunkResponse,proto3,oneof"` + MessageTreeSyncChunkResponse *MessageTreeSyncChunkResponse `protobuf:"bytes,50,opt,name=message_tree_sync_chunk_response,json=messageTreeSyncChunkResponse,proto3,oneof"` } type MessageWrapper_MessageBlobOffer struct { - MessageBlobOffer *MessageBlobOffer `protobuf:"bytes,33,opt,name=message_blob_offer,json=messageBlobOffer,proto3,oneof"` + MessageBlobOffer *MessageBlobOffer `protobuf:"bytes,51,opt,name=message_blob_offer,json=messageBlobOffer,proto3,oneof"` } type MessageWrapper_MessageBlobOfferResponse struct { - MessageBlobOfferResponse *MessageBlobOfferResponse `protobuf:"bytes,34,opt,name=message_blob_offer_response,json=messageBlobOfferResponse,proto3,oneof"` + MessageBlobOfferResponse *MessageBlobOfferResponse `protobuf:"bytes,52,opt,name=message_blob_offer_response,json=messageBlobOfferResponse,proto3,oneof"` } type MessageWrapper_MessageBlobChunkRequest struct { - MessageBlobChunkRequest *MessageBlobChunkRequest `protobuf:"bytes,35,opt,name=message_blob_chunk_request,json=messageBlobChunkRequest,proto3,oneof"` + MessageBlobChunkRequest *MessageBlobChunkRequest `protobuf:"bytes,53,opt,name=message_blob_chunk_request,json=messageBlobChunkRequest,proto3,oneof"` } type MessageWrapper_MessageBlobChunkResponse struct { - MessageBlobChunkResponse *MessageBlobChunkResponse `protobuf:"bytes,36,opt,name=message_blob_chunk_response,json=messageBlobChunkResponse,proto3,oneof"` + MessageBlobChunkResponse *MessageBlobChunkResponse `protobuf:"bytes,54,opt,name=message_blob_chunk_response,json=messageBlobChunkResponse,proto3,oneof"` } func (*MessageWrapper_MessageNewEpochWish) isMessageWrapper_Msg() {} @@ -331,9 +331,9 @@ func (*MessageWrapper_MessageCommit) isMessageWrapper_Msg() {} func (*MessageWrapper_MessageReportSignatures) isMessageWrapper_Msg() {} -func (*MessageWrapper_MessageCertifiedCommitRequest) isMessageWrapper_Msg() {} +func (*MessageWrapper_MessageReportsPlusPrecursorRequest) isMessageWrapper_Msg() {} -func (*MessageWrapper_MessageCertifiedCommit) isMessageWrapper_Msg() {} +func (*MessageWrapper_MessageReportsPlusPrecursor) isMessageWrapper_Msg() {} func (*MessageWrapper_MessageBlockSyncRequest) isMessageWrapper_Msg() {} @@ -470,6 +470,7 @@ type MessageEpochStart struct { Epoch uint64 `protobuf:"varint,1,opt,name=epoch,proto3" json:"epoch,omitempty"` EpochStartProof *EpochStartProof `protobuf:"bytes,2,opt,name=epoch_start_proof,json=epochStartProof,proto3" json:"epoch_start_proof,omitempty"` + Abdicate bool `protobuf:"varint,3,opt,name=abdicate,proto3" json:"abdicate,omitempty"` } func (x *MessageEpochStart) Reset() { @@ -518,6 +519,13 @@ func (x *MessageEpochStart) GetEpochStartProof() *EpochStartProof { return nil } +func (x *MessageEpochStart) GetAbdicate() bool { + if x != nil { + return x.Abdicate + } + return false +} + type MessageRoundStart struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -838,8 +846,9 @@ type MessageReportSignatures struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - SeqNr uint64 `protobuf:"varint,1,opt,name=seq_nr,json=seqNr,proto3" json:"seq_nr,omitempty"` - ReportSignatures [][]byte `protobuf:"bytes,2,rep,name=report_signatures,json=reportSignatures,proto3" json:"report_signatures,omitempty"` + SeqNr uint64 `protobuf:"varint,1,opt,name=seq_nr,json=seqNr,proto3" json:"seq_nr,omitempty"` + ReportSignatures [][]byte `protobuf:"bytes,2,rep,name=report_signatures,json=reportSignatures,proto3" json:"report_signatures,omitempty"` + ReportsPlusPrecursorDigest []byte `protobuf:"bytes,3,opt,name=reports_plus_precursor_digest,json=reportsPlusPrecursorDigest,proto3" json:"reports_plus_precursor_digest,omitempty"` } func (x *MessageReportSignatures) Reset() { @@ -888,7 +897,14 @@ func (x *MessageReportSignatures) GetReportSignatures() [][]byte { return nil } -type MessageCertifiedCommitRequest struct { +func (x *MessageReportSignatures) GetReportsPlusPrecursorDigest() []byte { + if x != nil { + return x.ReportsPlusPrecursorDigest + } + return nil +} + +type MessageReportsPlusPrecursorRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields @@ -896,8 +912,8 @@ type MessageCertifiedCommitRequest struct { SeqNr uint64 `protobuf:"varint,1,opt,name=seq_nr,json=seqNr,proto3" json:"seq_nr,omitempty"` } -func (x *MessageCertifiedCommitRequest) Reset() { - *x = MessageCertifiedCommitRequest{} +func (x *MessageReportsPlusPrecursorRequest) Reset() { + *x = MessageReportsPlusPrecursorRequest{} if protoimpl.UnsafeEnabled { mi := &file_offchainreporting3_1_messages_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -905,13 +921,13 @@ func (x *MessageCertifiedCommitRequest) Reset() { } } -func (x *MessageCertifiedCommitRequest) String() string { +func (x *MessageReportsPlusPrecursorRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*MessageCertifiedCommitRequest) ProtoMessage() {} +func (*MessageReportsPlusPrecursorRequest) ProtoMessage() {} -func (x *MessageCertifiedCommitRequest) ProtoReflect() protoreflect.Message { +func (x *MessageReportsPlusPrecursorRequest) ProtoReflect() protoreflect.Message { mi := &file_offchainreporting3_1_messages_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -923,28 +939,29 @@ func (x *MessageCertifiedCommitRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use MessageCertifiedCommitRequest.ProtoReflect.Descriptor instead. -func (*MessageCertifiedCommitRequest) Descriptor() ([]byte, []int) { +// Deprecated: Use MessageReportsPlusPrecursorRequest.ProtoReflect.Descriptor instead. +func (*MessageReportsPlusPrecursorRequest) Descriptor() ([]byte, []int) { return file_offchainreporting3_1_messages_proto_rawDescGZIP(), []int{10} } -func (x *MessageCertifiedCommitRequest) GetSeqNr() uint64 { +func (x *MessageReportsPlusPrecursorRequest) GetSeqNr() uint64 { if x != nil { return x.SeqNr } return 0 } -type MessageCertifiedCommit struct { +type MessageReportsPlusPrecursor struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - CertifiedCommittedReports *CertifiedCommittedReports `protobuf:"bytes,1,opt,name=certified_committed_reports,json=certifiedCommittedReports,proto3" json:"certified_committed_reports,omitempty"` + SeqNr uint64 `protobuf:"varint,1,opt,name=seq_nr,json=seqNr,proto3" json:"seq_nr,omitempty"` + ReportsPlusPrecursor []byte `protobuf:"bytes,2,opt,name=reports_plus_precursor,json=reportsPlusPrecursor,proto3" json:"reports_plus_precursor,omitempty"` } -func (x *MessageCertifiedCommit) Reset() { - *x = MessageCertifiedCommit{} +func (x *MessageReportsPlusPrecursor) Reset() { + *x = MessageReportsPlusPrecursor{} if protoimpl.UnsafeEnabled { mi := &file_offchainreporting3_1_messages_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -952,13 +969,13 @@ func (x *MessageCertifiedCommit) Reset() { } } -func (x *MessageCertifiedCommit) String() string { +func (x *MessageReportsPlusPrecursor) String() string { return protoimpl.X.MessageStringOf(x) } -func (*MessageCertifiedCommit) ProtoMessage() {} +func (*MessageReportsPlusPrecursor) ProtoMessage() {} -func (x *MessageCertifiedCommit) ProtoReflect() protoreflect.Message { +func (x *MessageReportsPlusPrecursor) ProtoReflect() protoreflect.Message { mi := &file_offchainreporting3_1_messages_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -970,14 +987,21 @@ func (x *MessageCertifiedCommit) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use MessageCertifiedCommit.ProtoReflect.Descriptor instead. -func (*MessageCertifiedCommit) Descriptor() ([]byte, []int) { +// Deprecated: Use MessageReportsPlusPrecursor.ProtoReflect.Descriptor instead. +func (*MessageReportsPlusPrecursor) Descriptor() ([]byte, []int) { return file_offchainreporting3_1_messages_proto_rawDescGZIP(), []int{11} } -func (x *MessageCertifiedCommit) GetCertifiedCommittedReports() *CertifiedCommittedReports { +func (x *MessageReportsPlusPrecursor) GetSeqNr() uint64 { if x != nil { - return x.CertifiedCommittedReports + return x.SeqNr + } + return 0 +} + +func (x *MessageReportsPlusPrecursor) GetReportsPlusPrecursor() []byte { + if x != nil { + return x.ReportsPlusPrecursor } return nil } @@ -1619,13 +1643,13 @@ type CertifiedPrepare struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Epoch uint64 `protobuf:"varint,1,opt,name=epoch,proto3" json:"epoch,omitempty"` - SeqNr uint64 `protobuf:"varint,2,opt,name=seq_nr,json=seqNr,proto3" json:"seq_nr,omitempty"` - StateTransitionInputsDigest []byte `protobuf:"bytes,3,opt,name=state_transition_inputs_digest,json=stateTransitionInputsDigest,proto3" json:"state_transition_inputs_digest,omitempty"` - StateTransitionOutputs *StateTransitionOutputs `protobuf:"bytes,4,opt,name=state_transition_outputs,json=stateTransitionOutputs,proto3" json:"state_transition_outputs,omitempty"` - StateRootDigest []byte `protobuf:"bytes,5,opt,name=state_root_digest,json=stateRootDigest,proto3" json:"state_root_digest,omitempty"` - ReportsPlusPrecursor []byte `protobuf:"bytes,6,opt,name=reports_plus_precursor,json=reportsPlusPrecursor,proto3" json:"reports_plus_precursor,omitempty"` - PrepareQuorumCertificate []*AttributedPrepareSignature `protobuf:"bytes,7,rep,name=prepare_quorum_certificate,json=prepareQuorumCertificate,proto3" json:"prepare_quorum_certificate,omitempty"` + Epoch uint64 `protobuf:"varint,1,opt,name=epoch,proto3" json:"epoch,omitempty"` + SeqNr uint64 `protobuf:"varint,2,opt,name=seq_nr,json=seqNr,proto3" json:"seq_nr,omitempty"` + StateTransitionInputsDigest []byte `protobuf:"bytes,3,opt,name=state_transition_inputs_digest,json=stateTransitionInputsDigest,proto3" json:"state_transition_inputs_digest,omitempty"` + StateTransitionOutputsDigest []byte `protobuf:"bytes,4,opt,name=state_transition_outputs_digest,json=stateTransitionOutputsDigest,proto3" json:"state_transition_outputs_digest,omitempty"` + StateRootDigest []byte `protobuf:"bytes,5,opt,name=state_root_digest,json=stateRootDigest,proto3" json:"state_root_digest,omitempty"` + ReportsPlusPrecursorDigest []byte `protobuf:"bytes,6,opt,name=reports_plus_precursor_digest,json=reportsPlusPrecursorDigest,proto3" json:"reports_plus_precursor_digest,omitempty"` + PrepareQuorumCertificate []*AttributedPrepareSignature `protobuf:"bytes,7,rep,name=prepare_quorum_certificate,json=prepareQuorumCertificate,proto3" json:"prepare_quorum_certificate,omitempty"` } func (x *CertifiedPrepare) Reset() { @@ -1681,9 +1705,9 @@ func (x *CertifiedPrepare) GetStateTransitionInputsDigest() []byte { return nil } -func (x *CertifiedPrepare) GetStateTransitionOutputs() *StateTransitionOutputs { +func (x *CertifiedPrepare) GetStateTransitionOutputsDigest() []byte { if x != nil { - return x.StateTransitionOutputs + return x.StateTransitionOutputsDigest } return nil } @@ -1695,9 +1719,9 @@ func (x *CertifiedPrepare) GetStateRootDigest() []byte { return nil } -func (x *CertifiedPrepare) GetReportsPlusPrecursor() []byte { +func (x *CertifiedPrepare) GetReportsPlusPrecursorDigest() []byte { if x != nil { - return x.ReportsPlusPrecursor + return x.ReportsPlusPrecursorDigest } return nil } @@ -1714,13 +1738,13 @@ type CertifiedCommit struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Epoch uint64 `protobuf:"varint,1,opt,name=epoch,proto3" json:"epoch,omitempty"` - SeqNr uint64 `protobuf:"varint,2,opt,name=seq_nr,json=seqNr,proto3" json:"seq_nr,omitempty"` - StateTransitionInputsDigest []byte `protobuf:"bytes,3,opt,name=state_transition_inputs_digest,json=stateTransitionInputsDigest,proto3" json:"state_transition_inputs_digest,omitempty"` - StateTransitionOutputs *StateTransitionOutputs `protobuf:"bytes,4,opt,name=state_transition_outputs,json=stateTransitionOutputs,proto3" json:"state_transition_outputs,omitempty"` - StateRootDigest []byte `protobuf:"bytes,5,opt,name=state_root_digest,json=stateRootDigest,proto3" json:"state_root_digest,omitempty"` - ReportsPlusPrecursor []byte `protobuf:"bytes,6,opt,name=reports_plus_precursor,json=reportsPlusPrecursor,proto3" json:"reports_plus_precursor,omitempty"` - CommitQuorumCertificate []*AttributedCommitSignature `protobuf:"bytes,7,rep,name=commit_quorum_certificate,json=commitQuorumCertificate,proto3" json:"commit_quorum_certificate,omitempty"` + Epoch uint64 `protobuf:"varint,1,opt,name=epoch,proto3" json:"epoch,omitempty"` + SeqNr uint64 `protobuf:"varint,2,opt,name=seq_nr,json=seqNr,proto3" json:"seq_nr,omitempty"` + StateTransitionInputsDigest []byte `protobuf:"bytes,3,opt,name=state_transition_inputs_digest,json=stateTransitionInputsDigest,proto3" json:"state_transition_inputs_digest,omitempty"` + StateTransitionOutputsDigest []byte `protobuf:"bytes,4,opt,name=state_transition_outputs_digest,json=stateTransitionOutputsDigest,proto3" json:"state_transition_outputs_digest,omitempty"` + StateRootDigest []byte `protobuf:"bytes,5,opt,name=state_root_digest,json=stateRootDigest,proto3" json:"state_root_digest,omitempty"` + ReportsPlusPrecursorDigest []byte `protobuf:"bytes,6,opt,name=reports_plus_precursor_digest,json=reportsPlusPrecursorDigest,proto3" json:"reports_plus_precursor_digest,omitempty"` + CommitQuorumCertificate []*AttributedCommitSignature `protobuf:"bytes,7,rep,name=commit_quorum_certificate,json=commitQuorumCertificate,proto3" json:"commit_quorum_certificate,omitempty"` } func (x *CertifiedCommit) Reset() { @@ -1776,9 +1800,9 @@ func (x *CertifiedCommit) GetStateTransitionInputsDigest() []byte { return nil } -func (x *CertifiedCommit) GetStateTransitionOutputs() *StateTransitionOutputs { +func (x *CertifiedCommit) GetStateTransitionOutputsDigest() []byte { if x != nil { - return x.StateTransitionOutputs + return x.StateTransitionOutputsDigest } return nil } @@ -1790,9 +1814,9 @@ func (x *CertifiedCommit) GetStateRootDigest() []byte { return nil } -func (x *CertifiedCommit) GetReportsPlusPrecursor() []byte { +func (x *CertifiedCommit) GetReportsPlusPrecursorDigest() []byte { if x != nil { - return x.ReportsPlusPrecursor + return x.ReportsPlusPrecursorDigest } return nil } @@ -1804,101 +1828,6 @@ func (x *CertifiedCommit) GetCommitQuorumCertificate() []*AttributedCommitSignat return nil } -type CertifiedCommittedReports struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - CommitEpoch uint64 `protobuf:"varint,1,opt,name=commit_epoch,json=commitEpoch,proto3" json:"commit_epoch,omitempty"` - SeqNr uint64 `protobuf:"varint,2,opt,name=seq_nr,json=seqNr,proto3" json:"seq_nr,omitempty"` - StateTransitionInputsDigest []byte `protobuf:"bytes,3,opt,name=state_transition_inputs_digest,json=stateTransitionInputsDigest,proto3" json:"state_transition_inputs_digest,omitempty"` - StateTransitionOutputDigest []byte `protobuf:"bytes,4,opt,name=state_transition_output_digest,json=stateTransitionOutputDigest,proto3" json:"state_transition_output_digest,omitempty"` - StateRootDigest []byte `protobuf:"bytes,5,opt,name=state_root_digest,json=stateRootDigest,proto3" json:"state_root_digest,omitempty"` - ReportsPlusPrecursor []byte `protobuf:"bytes,6,opt,name=reports_plus_precursor,json=reportsPlusPrecursor,proto3" json:"reports_plus_precursor,omitempty"` - CommitQuorumCertificate []*AttributedCommitSignature `protobuf:"bytes,7,rep,name=commit_quorum_certificate,json=commitQuorumCertificate,proto3" json:"commit_quorum_certificate,omitempty"` -} - -func (x *CertifiedCommittedReports) Reset() { - *x = CertifiedCommittedReports{} - if protoimpl.UnsafeEnabled { - mi := &file_offchainreporting3_1_messages_proto_msgTypes[24] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *CertifiedCommittedReports) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*CertifiedCommittedReports) ProtoMessage() {} - -func (x *CertifiedCommittedReports) ProtoReflect() protoreflect.Message { - mi := &file_offchainreporting3_1_messages_proto_msgTypes[24] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use CertifiedCommittedReports.ProtoReflect.Descriptor instead. -func (*CertifiedCommittedReports) Descriptor() ([]byte, []int) { - return file_offchainreporting3_1_messages_proto_rawDescGZIP(), []int{24} -} - -func (x *CertifiedCommittedReports) GetCommitEpoch() uint64 { - if x != nil { - return x.CommitEpoch - } - return 0 -} - -func (x *CertifiedCommittedReports) GetSeqNr() uint64 { - if x != nil { - return x.SeqNr - } - return 0 -} - -func (x *CertifiedCommittedReports) GetStateTransitionInputsDigest() []byte { - if x != nil { - return x.StateTransitionInputsDigest - } - return nil -} - -func (x *CertifiedCommittedReports) GetStateTransitionOutputDigest() []byte { - if x != nil { - return x.StateTransitionOutputDigest - } - return nil -} - -func (x *CertifiedCommittedReports) GetStateRootDigest() []byte { - if x != nil { - return x.StateRootDigest - } - return nil -} - -func (x *CertifiedCommittedReports) GetReportsPlusPrecursor() []byte { - if x != nil { - return x.ReportsPlusPrecursor - } - return nil -} - -func (x *CertifiedCommittedReports) GetCommitQuorumCertificate() []*AttributedCommitSignature { - if x != nil { - return x.CommitQuorumCertificate - } - return nil -} - type HighestCertifiedTimestamp struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1912,7 +1841,7 @@ type HighestCertifiedTimestamp struct { func (x *HighestCertifiedTimestamp) Reset() { *x = HighestCertifiedTimestamp{} if protoimpl.UnsafeEnabled { - mi := &file_offchainreporting3_1_messages_proto_msgTypes[25] + mi := &file_offchainreporting3_1_messages_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1925,7 +1854,7 @@ func (x *HighestCertifiedTimestamp) String() string { func (*HighestCertifiedTimestamp) ProtoMessage() {} func (x *HighestCertifiedTimestamp) ProtoReflect() protoreflect.Message { - mi := &file_offchainreporting3_1_messages_proto_msgTypes[25] + mi := &file_offchainreporting3_1_messages_proto_msgTypes[24] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1938,7 +1867,7 @@ func (x *HighestCertifiedTimestamp) ProtoReflect() protoreflect.Message { // Deprecated: Use HighestCertifiedTimestamp.ProtoReflect.Descriptor instead. func (*HighestCertifiedTimestamp) Descriptor() ([]byte, []int) { - return file_offchainreporting3_1_messages_proto_rawDescGZIP(), []int{25} + return file_offchainreporting3_1_messages_proto_rawDescGZIP(), []int{24} } func (x *HighestCertifiedTimestamp) GetSeqNr() uint64 { @@ -1974,7 +1903,7 @@ type AttributedSignedHighestCertifiedTimestamp struct { func (x *AttributedSignedHighestCertifiedTimestamp) Reset() { *x = AttributedSignedHighestCertifiedTimestamp{} if protoimpl.UnsafeEnabled { - mi := &file_offchainreporting3_1_messages_proto_msgTypes[26] + mi := &file_offchainreporting3_1_messages_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1987,7 +1916,7 @@ func (x *AttributedSignedHighestCertifiedTimestamp) String() string { func (*AttributedSignedHighestCertifiedTimestamp) ProtoMessage() {} func (x *AttributedSignedHighestCertifiedTimestamp) ProtoReflect() protoreflect.Message { - mi := &file_offchainreporting3_1_messages_proto_msgTypes[26] + mi := &file_offchainreporting3_1_messages_proto_msgTypes[25] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2000,7 +1929,7 @@ func (x *AttributedSignedHighestCertifiedTimestamp) ProtoReflect() protoreflect. // Deprecated: Use AttributedSignedHighestCertifiedTimestamp.ProtoReflect.Descriptor instead. func (*AttributedSignedHighestCertifiedTimestamp) Descriptor() ([]byte, []int) { - return file_offchainreporting3_1_messages_proto_rawDescGZIP(), []int{26} + return file_offchainreporting3_1_messages_proto_rawDescGZIP(), []int{25} } func (x *AttributedSignedHighestCertifiedTimestamp) GetSignedHighestCertifiedTimestamp() *SignedHighestCertifiedTimestamp { @@ -2029,7 +1958,7 @@ type SignedHighestCertifiedTimestamp struct { func (x *SignedHighestCertifiedTimestamp) Reset() { *x = SignedHighestCertifiedTimestamp{} if protoimpl.UnsafeEnabled { - mi := &file_offchainreporting3_1_messages_proto_msgTypes[27] + mi := &file_offchainreporting3_1_messages_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2042,7 +1971,7 @@ func (x *SignedHighestCertifiedTimestamp) String() string { func (*SignedHighestCertifiedTimestamp) ProtoMessage() {} func (x *SignedHighestCertifiedTimestamp) ProtoReflect() protoreflect.Message { - mi := &file_offchainreporting3_1_messages_proto_msgTypes[27] + mi := &file_offchainreporting3_1_messages_proto_msgTypes[26] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2055,7 +1984,7 @@ func (x *SignedHighestCertifiedTimestamp) ProtoReflect() protoreflect.Message { // Deprecated: Use SignedHighestCertifiedTimestamp.ProtoReflect.Descriptor instead. func (*SignedHighestCertifiedTimestamp) Descriptor() ([]byte, []int) { - return file_offchainreporting3_1_messages_proto_rawDescGZIP(), []int{27} + return file_offchainreporting3_1_messages_proto_rawDescGZIP(), []int{26} } func (x *SignedHighestCertifiedTimestamp) GetHighestCertifiedTimestamp() *HighestCertifiedTimestamp { @@ -2084,7 +2013,7 @@ type AttributedObservation struct { func (x *AttributedObservation) Reset() { *x = AttributedObservation{} if protoimpl.UnsafeEnabled { - mi := &file_offchainreporting3_1_messages_proto_msgTypes[28] + mi := &file_offchainreporting3_1_messages_proto_msgTypes[27] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2097,7 +2026,7 @@ func (x *AttributedObservation) String() string { func (*AttributedObservation) ProtoMessage() {} func (x *AttributedObservation) ProtoReflect() protoreflect.Message { - mi := &file_offchainreporting3_1_messages_proto_msgTypes[28] + mi := &file_offchainreporting3_1_messages_proto_msgTypes[27] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2110,7 +2039,7 @@ func (x *AttributedObservation) ProtoReflect() protoreflect.Message { // Deprecated: Use AttributedObservation.ProtoReflect.Descriptor instead. func (*AttributedObservation) Descriptor() ([]byte, []int) { - return file_offchainreporting3_1_messages_proto_rawDescGZIP(), []int{28} + return file_offchainreporting3_1_messages_proto_rawDescGZIP(), []int{27} } func (x *AttributedObservation) GetObservation() []byte { @@ -2139,7 +2068,7 @@ type AttributedSignedObservation struct { func (x *AttributedSignedObservation) Reset() { *x = AttributedSignedObservation{} if protoimpl.UnsafeEnabled { - mi := &file_offchainreporting3_1_messages_proto_msgTypes[29] + mi := &file_offchainreporting3_1_messages_proto_msgTypes[28] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2152,7 +2081,7 @@ func (x *AttributedSignedObservation) String() string { func (*AttributedSignedObservation) ProtoMessage() {} func (x *AttributedSignedObservation) ProtoReflect() protoreflect.Message { - mi := &file_offchainreporting3_1_messages_proto_msgTypes[29] + mi := &file_offchainreporting3_1_messages_proto_msgTypes[28] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2165,7 +2094,7 @@ func (x *AttributedSignedObservation) ProtoReflect() protoreflect.Message { // Deprecated: Use AttributedSignedObservation.ProtoReflect.Descriptor instead. func (*AttributedSignedObservation) Descriptor() ([]byte, []int) { - return file_offchainreporting3_1_messages_proto_rawDescGZIP(), []int{29} + return file_offchainreporting3_1_messages_proto_rawDescGZIP(), []int{28} } func (x *AttributedSignedObservation) GetSignedObservation() *SignedObservation { @@ -2194,7 +2123,7 @@ type SignedObservation struct { func (x *SignedObservation) Reset() { *x = SignedObservation{} if protoimpl.UnsafeEnabled { - mi := &file_offchainreporting3_1_messages_proto_msgTypes[30] + mi := &file_offchainreporting3_1_messages_proto_msgTypes[29] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2207,7 +2136,7 @@ func (x *SignedObservation) String() string { func (*SignedObservation) ProtoMessage() {} func (x *SignedObservation) ProtoReflect() protoreflect.Message { - mi := &file_offchainreporting3_1_messages_proto_msgTypes[30] + mi := &file_offchainreporting3_1_messages_proto_msgTypes[29] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2220,7 +2149,7 @@ func (x *SignedObservation) ProtoReflect() protoreflect.Message { // Deprecated: Use SignedObservation.ProtoReflect.Descriptor instead. func (*SignedObservation) Descriptor() ([]byte, []int) { - return file_offchainreporting3_1_messages_proto_rawDescGZIP(), []int{30} + return file_offchainreporting3_1_messages_proto_rawDescGZIP(), []int{29} } func (x *SignedObservation) GetObservation() []byte { @@ -2249,7 +2178,7 @@ type AttributedPrepareSignature struct { func (x *AttributedPrepareSignature) Reset() { *x = AttributedPrepareSignature{} if protoimpl.UnsafeEnabled { - mi := &file_offchainreporting3_1_messages_proto_msgTypes[31] + mi := &file_offchainreporting3_1_messages_proto_msgTypes[30] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2262,7 +2191,7 @@ func (x *AttributedPrepareSignature) String() string { func (*AttributedPrepareSignature) ProtoMessage() {} func (x *AttributedPrepareSignature) ProtoReflect() protoreflect.Message { - mi := &file_offchainreporting3_1_messages_proto_msgTypes[31] + mi := &file_offchainreporting3_1_messages_proto_msgTypes[30] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2275,7 +2204,7 @@ func (x *AttributedPrepareSignature) ProtoReflect() protoreflect.Message { // Deprecated: Use AttributedPrepareSignature.ProtoReflect.Descriptor instead. func (*AttributedPrepareSignature) Descriptor() ([]byte, []int) { - return file_offchainreporting3_1_messages_proto_rawDescGZIP(), []int{31} + return file_offchainreporting3_1_messages_proto_rawDescGZIP(), []int{30} } func (x *AttributedPrepareSignature) GetSignature() []byte { @@ -2304,7 +2233,7 @@ type AttributedCommitSignature struct { func (x *AttributedCommitSignature) Reset() { *x = AttributedCommitSignature{} if protoimpl.UnsafeEnabled { - mi := &file_offchainreporting3_1_messages_proto_msgTypes[32] + mi := &file_offchainreporting3_1_messages_proto_msgTypes[31] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2317,7 +2246,7 @@ func (x *AttributedCommitSignature) String() string { func (*AttributedCommitSignature) ProtoMessage() {} func (x *AttributedCommitSignature) ProtoReflect() protoreflect.Message { - mi := &file_offchainreporting3_1_messages_proto_msgTypes[32] + mi := &file_offchainreporting3_1_messages_proto_msgTypes[31] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2330,7 +2259,7 @@ func (x *AttributedCommitSignature) ProtoReflect() protoreflect.Message { // Deprecated: Use AttributedCommitSignature.ProtoReflect.Descriptor instead. func (*AttributedCommitSignature) Descriptor() ([]byte, []int) { - return file_offchainreporting3_1_messages_proto_rawDescGZIP(), []int{32} + return file_offchainreporting3_1_messages_proto_rawDescGZIP(), []int{31} } func (x *AttributedCommitSignature) GetSignature() []byte { @@ -2359,7 +2288,7 @@ type AttestedStateTransitionBlock struct { func (x *AttestedStateTransitionBlock) Reset() { *x = AttestedStateTransitionBlock{} if protoimpl.UnsafeEnabled { - mi := &file_offchainreporting3_1_messages_proto_msgTypes[33] + mi := &file_offchainreporting3_1_messages_proto_msgTypes[32] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2372,7 +2301,7 @@ func (x *AttestedStateTransitionBlock) String() string { func (*AttestedStateTransitionBlock) ProtoMessage() {} func (x *AttestedStateTransitionBlock) ProtoReflect() protoreflect.Message { - mi := &file_offchainreporting3_1_messages_proto_msgTypes[33] + mi := &file_offchainreporting3_1_messages_proto_msgTypes[32] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2385,7 +2314,7 @@ func (x *AttestedStateTransitionBlock) ProtoReflect() protoreflect.Message { // Deprecated: Use AttestedStateTransitionBlock.ProtoReflect.Descriptor instead. func (*AttestedStateTransitionBlock) Descriptor() ([]byte, []int) { - return file_offchainreporting3_1_messages_proto_rawDescGZIP(), []int{33} + return file_offchainreporting3_1_messages_proto_rawDescGZIP(), []int{32} } func (x *AttestedStateTransitionBlock) GetStateTransitionBlock() *StateTransitionBlock { @@ -2412,13 +2341,13 @@ type StateTransitionBlock struct { StateTransitionInputsDigest []byte `protobuf:"bytes,3,opt,name=state_transition_inputs_digest,json=stateTransitionInputsDigest,proto3" json:"state_transition_inputs_digest,omitempty"` StateTransitionOutputs *StateTransitionOutputs `protobuf:"bytes,4,opt,name=state_transition_outputs,json=stateTransitionOutputs,proto3" json:"state_transition_outputs,omitempty"` StateRootDigest []byte `protobuf:"bytes,5,opt,name=state_root_digest,json=stateRootDigest,proto3" json:"state_root_digest,omitempty"` - ReportsPlusPrecursor []byte `protobuf:"bytes,6,opt,name=reports_plus_precursor,json=reportsPlusPrecursor,proto3" json:"reports_plus_precursor,omitempty"` + ReportsPlusPrecursorDigest []byte `protobuf:"bytes,6,opt,name=reports_plus_precursor_digest,json=reportsPlusPrecursorDigest,proto3" json:"reports_plus_precursor_digest,omitempty"` } func (x *StateTransitionBlock) Reset() { *x = StateTransitionBlock{} if protoimpl.UnsafeEnabled { - mi := &file_offchainreporting3_1_messages_proto_msgTypes[34] + mi := &file_offchainreporting3_1_messages_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2431,7 +2360,7 @@ func (x *StateTransitionBlock) String() string { func (*StateTransitionBlock) ProtoMessage() {} func (x *StateTransitionBlock) ProtoReflect() protoreflect.Message { - mi := &file_offchainreporting3_1_messages_proto_msgTypes[34] + mi := &file_offchainreporting3_1_messages_proto_msgTypes[33] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2444,7 +2373,7 @@ func (x *StateTransitionBlock) ProtoReflect() protoreflect.Message { // Deprecated: Use StateTransitionBlock.ProtoReflect.Descriptor instead. func (*StateTransitionBlock) Descriptor() ([]byte, []int) { - return file_offchainreporting3_1_messages_proto_rawDescGZIP(), []int{34} + return file_offchainreporting3_1_messages_proto_rawDescGZIP(), []int{33} } func (x *StateTransitionBlock) GetEpoch() uint64 { @@ -2482,9 +2411,9 @@ func (x *StateTransitionBlock) GetStateRootDigest() []byte { return nil } -func (x *StateTransitionBlock) GetReportsPlusPrecursor() []byte { +func (x *StateTransitionBlock) GetReportsPlusPrecursorDigest() []byte { if x != nil { - return x.ReportsPlusPrecursor + return x.ReportsPlusPrecursorDigest } return nil } @@ -2500,7 +2429,7 @@ type StateTransitionOutputs struct { func (x *StateTransitionOutputs) Reset() { *x = StateTransitionOutputs{} if protoimpl.UnsafeEnabled { - mi := &file_offchainreporting3_1_messages_proto_msgTypes[35] + mi := &file_offchainreporting3_1_messages_proto_msgTypes[34] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2513,7 +2442,7 @@ func (x *StateTransitionOutputs) String() string { func (*StateTransitionOutputs) ProtoMessage() {} func (x *StateTransitionOutputs) ProtoReflect() protoreflect.Message { - mi := &file_offchainreporting3_1_messages_proto_msgTypes[35] + mi := &file_offchainreporting3_1_messages_proto_msgTypes[34] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2526,7 +2455,7 @@ func (x *StateTransitionOutputs) ProtoReflect() protoreflect.Message { // Deprecated: Use StateTransitionOutputs.ProtoReflect.Descriptor instead. func (*StateTransitionOutputs) Descriptor() ([]byte, []int) { - return file_offchainreporting3_1_messages_proto_rawDescGZIP(), []int{35} + return file_offchainreporting3_1_messages_proto_rawDescGZIP(), []int{34} } func (x *StateTransitionOutputs) GetWriteSet() []*KeyValueModification { @@ -2549,7 +2478,7 @@ type KeyValueModification struct { func (x *KeyValueModification) Reset() { *x = KeyValueModification{} if protoimpl.UnsafeEnabled { - mi := &file_offchainreporting3_1_messages_proto_msgTypes[36] + mi := &file_offchainreporting3_1_messages_proto_msgTypes[35] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2562,7 +2491,7 @@ func (x *KeyValueModification) String() string { func (*KeyValueModification) ProtoMessage() {} func (x *KeyValueModification) ProtoReflect() protoreflect.Message { - mi := &file_offchainreporting3_1_messages_proto_msgTypes[36] + mi := &file_offchainreporting3_1_messages_proto_msgTypes[35] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2575,7 +2504,7 @@ func (x *KeyValueModification) ProtoReflect() protoreflect.Message { // Deprecated: Use KeyValueModification.ProtoReflect.Descriptor instead. func (*KeyValueModification) Descriptor() ([]byte, []int) { - return file_offchainreporting3_1_messages_proto_rawDescGZIP(), []int{36} + return file_offchainreporting3_1_messages_proto_rawDescGZIP(), []int{35} } func (x *KeyValueModification) GetKey() []byte { @@ -2614,7 +2543,7 @@ type StateTransitionInputs struct { func (x *StateTransitionInputs) Reset() { *x = StateTransitionInputs{} if protoimpl.UnsafeEnabled { - mi := &file_offchainreporting3_1_messages_proto_msgTypes[37] + mi := &file_offchainreporting3_1_messages_proto_msgTypes[36] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2627,7 +2556,7 @@ func (x *StateTransitionInputs) String() string { func (*StateTransitionInputs) ProtoMessage() {} func (x *StateTransitionInputs) ProtoReflect() protoreflect.Message { - mi := &file_offchainreporting3_1_messages_proto_msgTypes[37] + mi := &file_offchainreporting3_1_messages_proto_msgTypes[36] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2640,7 +2569,7 @@ func (x *StateTransitionInputs) ProtoReflect() protoreflect.Message { // Deprecated: Use StateTransitionInputs.ProtoReflect.Descriptor instead. func (*StateTransitionInputs) Descriptor() ([]byte, []int) { - return file_offchainreporting3_1_messages_proto_rawDescGZIP(), []int{37} + return file_offchainreporting3_1_messages_proto_rawDescGZIP(), []int{36} } func (x *StateTransitionInputs) GetSeqNr() uint64 { @@ -2683,15 +2612,15 @@ type MessageBlobOffer struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - ChunkDigests [][]byte `protobuf:"bytes,1,rep,name=chunk_digests,json=chunkDigests,proto3" json:"chunk_digests,omitempty"` - PayloadLength uint64 `protobuf:"varint,2,opt,name=payload_length,json=payloadLength,proto3" json:"payload_length,omitempty"` - ExpirySeqNr uint64 `protobuf:"varint,3,opt,name=expiry_seq_nr,json=expirySeqNr,proto3" json:"expiry_seq_nr,omitempty"` + ChunkDigestsRoot []byte `protobuf:"bytes,1,opt,name=chunk_digests_root,json=chunkDigestsRoot,proto3" json:"chunk_digests_root,omitempty"` + PayloadLength uint64 `protobuf:"varint,2,opt,name=payload_length,json=payloadLength,proto3" json:"payload_length,omitempty"` + ExpirySeqNr uint64 `protobuf:"varint,3,opt,name=expiry_seq_nr,json=expirySeqNr,proto3" json:"expiry_seq_nr,omitempty"` } func (x *MessageBlobOffer) Reset() { *x = MessageBlobOffer{} if protoimpl.UnsafeEnabled { - mi := &file_offchainreporting3_1_messages_proto_msgTypes[38] + mi := &file_offchainreporting3_1_messages_proto_msgTypes[37] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2704,7 +2633,7 @@ func (x *MessageBlobOffer) String() string { func (*MessageBlobOffer) ProtoMessage() {} func (x *MessageBlobOffer) ProtoReflect() protoreflect.Message { - mi := &file_offchainreporting3_1_messages_proto_msgTypes[38] + mi := &file_offchainreporting3_1_messages_proto_msgTypes[37] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2717,12 +2646,12 @@ func (x *MessageBlobOffer) ProtoReflect() protoreflect.Message { // Deprecated: Use MessageBlobOffer.ProtoReflect.Descriptor instead. func (*MessageBlobOffer) Descriptor() ([]byte, []int) { - return file_offchainreporting3_1_messages_proto_rawDescGZIP(), []int{38} + return file_offchainreporting3_1_messages_proto_rawDescGZIP(), []int{37} } -func (x *MessageBlobOffer) GetChunkDigests() [][]byte { +func (x *MessageBlobOffer) GetChunkDigestsRoot() []byte { if x != nil { - return x.ChunkDigests + return x.ChunkDigestsRoot } return nil } @@ -2753,7 +2682,7 @@ type MessageBlobChunkRequest struct { func (x *MessageBlobChunkRequest) Reset() { *x = MessageBlobChunkRequest{} if protoimpl.UnsafeEnabled { - mi := &file_offchainreporting3_1_messages_proto_msgTypes[39] + mi := &file_offchainreporting3_1_messages_proto_msgTypes[38] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2766,7 +2695,7 @@ func (x *MessageBlobChunkRequest) String() string { func (*MessageBlobChunkRequest) ProtoMessage() {} func (x *MessageBlobChunkRequest) ProtoReflect() protoreflect.Message { - mi := &file_offchainreporting3_1_messages_proto_msgTypes[39] + mi := &file_offchainreporting3_1_messages_proto_msgTypes[38] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2779,7 +2708,7 @@ func (x *MessageBlobChunkRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use MessageBlobChunkRequest.ProtoReflect.Descriptor instead. func (*MessageBlobChunkRequest) Descriptor() ([]byte, []int) { - return file_offchainreporting3_1_messages_proto_rawDescGZIP(), []int{39} + return file_offchainreporting3_1_messages_proto_rawDescGZIP(), []int{38} } func (x *MessageBlobChunkRequest) GetBlobDigest() []byte { @@ -2801,16 +2730,17 @@ type MessageBlobChunkResponse struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - BlobDigest []byte `protobuf:"bytes,1,opt,name=blob_digest,json=blobDigest,proto3" json:"blob_digest,omitempty"` - ChunkIndex uint64 `protobuf:"varint,2,opt,name=chunk_index,json=chunkIndex,proto3" json:"chunk_index,omitempty"` - GoAway bool `protobuf:"varint,3,opt,name=go_away,json=goAway,proto3" json:"go_away,omitempty"` - Chunk []byte `protobuf:"bytes,4,opt,name=chunk,proto3" json:"chunk,omitempty"` + BlobDigest []byte `protobuf:"bytes,1,opt,name=blob_digest,json=blobDigest,proto3" json:"blob_digest,omitempty"` + ChunkIndex uint64 `protobuf:"varint,2,opt,name=chunk_index,json=chunkIndex,proto3" json:"chunk_index,omitempty"` + GoAway bool `protobuf:"varint,3,opt,name=go_away,json=goAway,proto3" json:"go_away,omitempty"` + Chunk []byte `protobuf:"bytes,4,opt,name=chunk,proto3" json:"chunk,omitempty"` + Proof [][]byte `protobuf:"bytes,5,rep,name=proof,proto3" json:"proof,omitempty"` } func (x *MessageBlobChunkResponse) Reset() { *x = MessageBlobChunkResponse{} if protoimpl.UnsafeEnabled { - mi := &file_offchainreporting3_1_messages_proto_msgTypes[40] + mi := &file_offchainreporting3_1_messages_proto_msgTypes[39] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2823,7 +2753,7 @@ func (x *MessageBlobChunkResponse) String() string { func (*MessageBlobChunkResponse) ProtoMessage() {} func (x *MessageBlobChunkResponse) ProtoReflect() protoreflect.Message { - mi := &file_offchainreporting3_1_messages_proto_msgTypes[40] + mi := &file_offchainreporting3_1_messages_proto_msgTypes[39] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2836,7 +2766,7 @@ func (x *MessageBlobChunkResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use MessageBlobChunkResponse.ProtoReflect.Descriptor instead. func (*MessageBlobChunkResponse) Descriptor() ([]byte, []int) { - return file_offchainreporting3_1_messages_proto_rawDescGZIP(), []int{40} + return file_offchainreporting3_1_messages_proto_rawDescGZIP(), []int{39} } func (x *MessageBlobChunkResponse) GetBlobDigest() []byte { @@ -2867,6 +2797,13 @@ func (x *MessageBlobChunkResponse) GetChunk() []byte { return nil } +func (x *MessageBlobChunkResponse) GetProof() [][]byte { + if x != nil { + return x.Proof + } + return nil +} + type MessageBlobOfferResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -2880,7 +2817,7 @@ type MessageBlobOfferResponse struct { func (x *MessageBlobOfferResponse) Reset() { *x = MessageBlobOfferResponse{} if protoimpl.UnsafeEnabled { - mi := &file_offchainreporting3_1_messages_proto_msgTypes[41] + mi := &file_offchainreporting3_1_messages_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2893,7 +2830,7 @@ func (x *MessageBlobOfferResponse) String() string { func (*MessageBlobOfferResponse) ProtoMessage() {} func (x *MessageBlobOfferResponse) ProtoReflect() protoreflect.Message { - mi := &file_offchainreporting3_1_messages_proto_msgTypes[41] + mi := &file_offchainreporting3_1_messages_proto_msgTypes[40] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2906,7 +2843,7 @@ func (x *MessageBlobOfferResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use MessageBlobOfferResponse.ProtoReflect.Descriptor instead. func (*MessageBlobOfferResponse) Descriptor() ([]byte, []int) { - return file_offchainreporting3_1_messages_proto_rawDescGZIP(), []int{41} + return file_offchainreporting3_1_messages_proto_rawDescGZIP(), []int{40} } func (x *MessageBlobOfferResponse) GetBlobDigest() []byte { @@ -2936,567 +2873,546 @@ var file_offchainreporting3_1_messages_proto_rawDesc = []byte{ 0x0a, 0x23, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x14, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, - 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x22, 0xc1, 0x10, 0x0a, 0x0e, + 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x22, 0xe2, 0x10, 0x0a, 0x0e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x57, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x12, 0x60, 0x0a, 0x16, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x6e, 0x65, 0x77, 0x5f, 0x65, 0x70, - 0x6f, 0x63, 0x68, 0x5f, 0x77, 0x69, 0x73, 0x68, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, + 0x6f, 0x63, 0x68, 0x5f, 0x77, 0x69, 0x73, 0x68, 0x18, 0x23, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x4e, 0x65, 0x77, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x57, 0x69, 0x73, 0x68, 0x48, 0x00, 0x52, 0x13, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x4e, 0x65, 0x77, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x57, 0x69, 0x73, 0x68, 0x12, 0x6f, 0x0a, 0x1b, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, - 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, + 0x24, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x18, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x59, 0x0a, 0x13, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x65, 0x70, 0x6f, - 0x63, 0x68, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, + 0x63, 0x68, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x25, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x53, 0x74, 0x61, 0x72, 0x74, 0x48, 0x00, 0x52, 0x11, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x53, 0x74, 0x61, 0x72, 0x74, 0x12, 0x59, 0x0a, 0x13, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x73, 0x74, - 0x61, 0x72, 0x74, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x6f, 0x66, 0x66, 0x63, + 0x61, 0x72, 0x74, 0x18, 0x26, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x53, 0x74, 0x61, 0x72, 0x74, 0x48, 0x00, 0x52, 0x11, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x53, 0x74, 0x61, 0x72, 0x74, 0x12, 0x5b, 0x0a, 0x13, 0x6d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x5f, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x15, + 0x67, 0x65, 0x5f, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x27, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x12, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x52, 0x0a, 0x10, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, - 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, + 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x18, 0x28, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x48, 0x00, 0x52, 0x0f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x12, 0x4f, 0x0a, 0x0f, 0x6d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x5f, 0x70, 0x72, 0x65, 0x70, 0x61, 0x72, 0x65, 0x18, 0x17, 0x20, 0x01, 0x28, + 0x61, 0x67, 0x65, 0x5f, 0x70, 0x72, 0x65, 0x70, 0x61, 0x72, 0x65, 0x18, 0x29, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x50, 0x72, 0x65, 0x70, 0x61, 0x72, 0x65, 0x48, 0x00, 0x52, 0x0e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x50, 0x72, 0x65, 0x70, 0x61, 0x72, 0x65, 0x12, 0x4c, 0x0a, 0x0e, 0x6d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x18, 0x18, 0x20, 0x01, 0x28, + 0x73, 0x61, 0x67, 0x65, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x18, 0x2a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x48, 0x00, 0x52, 0x0d, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x12, 0x6b, 0x0a, 0x19, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, - 0x75, 0x72, 0x65, 0x73, 0x18, 0x19, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x6f, 0x66, 0x66, + 0x75, 0x72, 0x65, 0x73, 0x18, 0x2b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x48, 0x00, 0x52, 0x17, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, - 0x75, 0x72, 0x65, 0x73, 0x12, 0x7e, 0x0a, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, - 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, - 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, - 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, - 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x65, 0x72, - 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x1d, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x65, - 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x68, 0x0a, 0x18, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, - 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, - 0x18, 0x1b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, - 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x43, 0x6f, - 0x6d, 0x6d, 0x69, 0x74, 0x48, 0x00, 0x52, 0x16, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, - 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x12, 0x6c, - 0x0a, 0x1a, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, - 0x73, 0x79, 0x6e, 0x63, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x1c, 0x20, 0x01, + 0x75, 0x72, 0x65, 0x73, 0x12, 0x8e, 0x01, 0x0a, 0x26, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x5f, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x5f, 0x70, 0x6c, 0x75, 0x73, 0x5f, 0x70, 0x72, + 0x65, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, + 0x2c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, + 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x50, 0x6c, 0x75, 0x73, 0x50, + 0x72, 0x65, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, + 0x00, 0x52, 0x22, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, + 0x73, 0x50, 0x6c, 0x75, 0x73, 0x50, 0x72, 0x65, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x78, 0x0a, 0x1e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x5f, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x5f, 0x70, 0x6c, 0x75, 0x73, 0x5f, 0x70, 0x72, + 0x65, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x18, 0x2d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, + 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, + 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x70, 0x6f, + 0x72, 0x74, 0x73, 0x50, 0x6c, 0x75, 0x73, 0x50, 0x72, 0x65, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, + 0x48, 0x00, 0x52, 0x1b, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x72, + 0x74, 0x73, 0x50, 0x6c, 0x75, 0x73, 0x50, 0x72, 0x65, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x12, + 0x6c, 0x0a, 0x1a, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x5f, 0x73, 0x79, 0x6e, 0x63, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x2e, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, + 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x48, 0x00, 0x52, 0x17, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6f, 0x0a, + 0x1b, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x73, + 0x79, 0x6e, 0x63, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x2f, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, + 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x48, 0x00, 0x52, 0x18, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, + 0x0a, 0x1a, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, + 0x73, 0x79, 0x6e, 0x63, 0x5f, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x30, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x48, 0x00, 0x52, 0x17, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6f, 0x0a, 0x1b, - 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x73, 0x79, - 0x6e, 0x63, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x1d, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x2e, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, + 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, + 0x79, 0x48, 0x00, 0x52, 0x17, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x53, 0x74, 0x61, 0x74, + 0x65, 0x53, 0x79, 0x6e, 0x63, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x79, 0x0a, 0x1f, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x72, 0x65, 0x65, 0x5f, 0x73, 0x79, 0x6e, + 0x63, 0x5f, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, + 0x31, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, + 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x54, 0x72, 0x65, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x43, 0x68, 0x75, 0x6e, + 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x1b, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x54, 0x72, 0x65, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x43, 0x68, 0x75, 0x6e, 0x6b, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x7c, 0x0a, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x5f, 0x74, 0x72, 0x65, 0x65, 0x5f, 0x73, 0x79, 0x6e, 0x63, 0x5f, 0x63, 0x68, 0x75, + 0x6e, 0x6b, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x32, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x32, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x48, 0x00, 0x52, 0x18, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x6c, 0x6f, 0x63, - 0x6b, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, - 0x1a, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x73, - 0x79, 0x6e, 0x63, 0x5f, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x1e, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x2d, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, + 0x54, 0x72, 0x65, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x1c, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x54, 0x72, 0x65, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x12, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x5f, 0x62, 0x6c, 0x6f, 0x62, 0x5f, 0x6f, 0x66, 0x66, 0x65, 0x72, 0x18, 0x33, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x26, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x53, 0x74, 0x61, 0x74, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, - 0x48, 0x00, 0x52, 0x17, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, - 0x53, 0x79, 0x6e, 0x63, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x79, 0x0a, 0x1f, 0x6d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x72, 0x65, 0x65, 0x5f, 0x73, 0x79, 0x6e, 0x63, - 0x5f, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x1f, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, - 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x54, 0x72, 0x65, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x43, 0x68, 0x75, 0x6e, 0x6b, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x1b, 0x6d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x54, 0x72, 0x65, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x7c, 0x0a, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x5f, 0x74, 0x72, 0x65, 0x65, 0x5f, 0x73, 0x79, 0x6e, 0x63, 0x5f, 0x63, 0x68, 0x75, 0x6e, - 0x6b, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x20, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x32, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, - 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, - 0x72, 0x65, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x1c, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, - 0x72, 0x65, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x12, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, - 0x62, 0x6c, 0x6f, 0x62, 0x5f, 0x6f, 0x66, 0x66, 0x65, 0x72, 0x18, 0x21, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x26, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, - 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, - 0x6c, 0x6f, 0x62, 0x4f, 0x66, 0x66, 0x65, 0x72, 0x48, 0x00, 0x52, 0x10, 0x6d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x42, 0x6c, 0x6f, 0x62, 0x4f, 0x66, 0x66, 0x65, 0x72, 0x12, 0x6f, 0x0a, 0x1b, - 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x62, 0x6c, 0x6f, 0x62, 0x5f, 0x6f, 0x66, 0x66, - 0x65, 0x72, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x22, 0x20, 0x01, 0x28, + 0x42, 0x6c, 0x6f, 0x62, 0x4f, 0x66, 0x66, 0x65, 0x72, 0x48, 0x00, 0x52, 0x10, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x42, 0x6c, 0x6f, 0x62, 0x4f, 0x66, 0x66, 0x65, 0x72, 0x12, 0x6f, 0x0a, + 0x1b, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x62, 0x6c, 0x6f, 0x62, 0x5f, 0x6f, 0x66, + 0x66, 0x65, 0x72, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x34, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, + 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x42, 0x6c, 0x6f, 0x62, 0x4f, 0x66, 0x66, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x48, 0x00, 0x52, 0x18, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x6c, 0x6f, + 0x62, 0x4f, 0x66, 0x66, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, + 0x0a, 0x1a, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x62, 0x6c, 0x6f, 0x62, 0x5f, 0x63, + 0x68, 0x75, 0x6e, 0x6b, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x35, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, + 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x42, 0x6c, 0x6f, 0x62, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x48, 0x00, 0x52, 0x17, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x6c, 0x6f, 0x62, + 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6f, 0x0a, 0x1b, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x62, 0x6c, 0x6f, 0x62, 0x5f, 0x63, 0x68, 0x75, + 0x6e, 0x6b, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x36, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x42, 0x6c, 0x6f, 0x62, 0x4f, 0x66, 0x66, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x42, 0x6c, 0x6f, 0x62, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x18, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x6c, 0x6f, 0x62, - 0x4f, 0x66, 0x66, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, - 0x1a, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x62, 0x6c, 0x6f, 0x62, 0x5f, 0x63, 0x68, - 0x75, 0x6e, 0x6b, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x23, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x2d, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, - 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x42, 0x6c, 0x6f, 0x62, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x48, 0x00, 0x52, 0x17, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x6c, 0x6f, 0x62, 0x43, - 0x68, 0x75, 0x6e, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x6f, 0x0a, 0x1b, 0x6d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x62, 0x6c, 0x6f, 0x62, 0x5f, 0x63, 0x68, 0x75, 0x6e, - 0x6b, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x24, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x2e, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, - 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, - 0x6c, 0x6f, 0x62, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x48, 0x00, 0x52, 0x18, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x6c, 0x6f, 0x62, 0x43, - 0x68, 0x75, 0x6e, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x05, 0x0a, 0x03, - 0x6d, 0x73, 0x67, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x09, 0x4a, 0x04, 0x08, 0x09, 0x10, 0x11, 0x22, - 0x2b, 0x0a, 0x13, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x4e, 0x65, 0x77, 0x45, 0x70, 0x6f, - 0x63, 0x68, 0x57, 0x69, 0x73, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x22, 0x92, 0x02, 0x0a, - 0x18, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x53, 0x74, 0x61, - 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x70, 0x6f, - 0x63, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x12, - 0x5b, 0x0a, 0x11, 0x68, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x69, - 0x66, 0x69, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x6f, 0x66, 0x66, + 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x05, 0x0a, + 0x03, 0x6d, 0x73, 0x67, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x1c, 0x4a, 0x04, 0x08, 0x1c, 0x10, 0x23, + 0x22, 0x2b, 0x0a, 0x13, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x4e, 0x65, 0x77, 0x45, 0x70, + 0x6f, 0x63, 0x68, 0x57, 0x69, 0x73, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x22, 0x92, 0x02, + 0x0a, 0x18, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x53, 0x74, + 0x61, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x70, + 0x6f, 0x63, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, + 0x12, 0x5b, 0x0a, 0x11, 0x68, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x5f, 0x63, 0x65, 0x72, 0x74, + 0x69, 0x66, 0x69, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x6f, 0x66, + 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, + 0x5f, 0x31, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x50, 0x72, 0x65, 0x70, + 0x61, 0x72, 0x65, 0x4f, 0x72, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x52, 0x10, 0x68, 0x69, 0x67, + 0x68, 0x65, 0x73, 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x12, 0x82, 0x01, + 0x0a, 0x22, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x68, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, + 0x5f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, - 0x31, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x50, 0x72, 0x65, 0x70, 0x61, - 0x72, 0x65, 0x4f, 0x72, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x52, 0x10, 0x68, 0x69, 0x67, 0x68, - 0x65, 0x73, 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x12, 0x82, 0x01, 0x0a, - 0x22, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x68, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x5f, - 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x6f, 0x66, 0x66, 0x63, - 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, - 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x48, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x43, 0x65, - 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, - 0x52, 0x1f, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x48, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x43, + 0x31, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x48, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x22, 0x7c, 0x0a, 0x11, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x45, 0x70, 0x6f, 0x63, - 0x68, 0x53, 0x74, 0x61, 0x72, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x12, 0x51, 0x0a, 0x11, - 0x65, 0x70, 0x6f, 0x63, 0x68, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x70, 0x72, 0x6f, 0x6f, - 0x66, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, - 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x45, - 0x70, 0x6f, 0x63, 0x68, 0x53, 0x74, 0x61, 0x72, 0x74, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x0f, - 0x65, 0x70, 0x6f, 0x63, 0x68, 0x53, 0x74, 0x61, 0x72, 0x74, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x22, - 0x56, 0x0a, 0x11, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x53, - 0x74, 0x61, 0x72, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x12, 0x15, 0x0a, 0x06, 0x73, 0x65, - 0x71, 0x5f, 0x6e, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x73, 0x65, 0x71, 0x4e, - 0x72, 0x12, 0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x22, 0x99, 0x01, 0x0a, 0x12, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, - 0x0a, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x65, - 0x70, 0x6f, 0x63, 0x68, 0x12, 0x15, 0x0a, 0x06, 0x73, 0x65, 0x71, 0x5f, 0x6e, 0x72, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x73, 0x65, 0x71, 0x4e, 0x72, 0x12, 0x56, 0x0a, 0x12, 0x73, - 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, - 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x53, - 0x69, 0x67, 0x6e, 0x65, 0x64, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x11, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x22, 0xb7, 0x01, 0x0a, 0x0f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x50, - 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x12, 0x15, 0x0a, - 0x06, 0x73, 0x65, 0x71, 0x5f, 0x6e, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x73, - 0x65, 0x71, 0x4e, 0x72, 0x12, 0x77, 0x0a, 0x1e, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, - 0x65, 0x64, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x6f, - 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, - 0x33, 0x5f, 0x31, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x64, 0x53, 0x69, - 0x67, 0x6e, 0x65, 0x64, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x1c, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x64, 0x53, 0x69, 0x67, 0x6e, 0x65, - 0x64, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x5b, 0x0a, - 0x0e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x50, 0x72, 0x65, 0x70, 0x61, 0x72, 0x65, 0x12, - 0x14, 0x0a, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, - 0x65, 0x70, 0x6f, 0x63, 0x68, 0x12, 0x15, 0x0a, 0x06, 0x73, 0x65, 0x71, 0x5f, 0x6e, 0x72, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x73, 0x65, 0x71, 0x4e, 0x72, 0x12, 0x1c, 0x0a, 0x09, - 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x5a, 0x0a, 0x0d, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x65, - 0x70, 0x6f, 0x63, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x65, 0x70, 0x6f, 0x63, - 0x68, 0x12, 0x15, 0x0a, 0x06, 0x73, 0x65, 0x71, 0x5f, 0x6e, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x05, 0x73, 0x65, 0x71, 0x4e, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, - 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, - 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x5d, 0x0a, 0x17, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, - 0x73, 0x12, 0x15, 0x0a, 0x06, 0x73, 0x65, 0x71, 0x5f, 0x6e, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x05, 0x73, 0x65, 0x71, 0x4e, 0x72, 0x12, 0x2b, 0x0a, 0x11, 0x72, 0x65, 0x70, 0x6f, - 0x72, 0x74, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x18, 0x02, 0x20, - 0x03, 0x28, 0x0c, 0x52, 0x10, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x61, - 0x74, 0x75, 0x72, 0x65, 0x73, 0x22, 0x36, 0x0a, 0x1d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, 0x06, 0x73, 0x65, 0x71, 0x5f, 0x6e, 0x72, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x73, 0x65, 0x71, 0x4e, 0x72, 0x22, 0x89, 0x01, - 0x0a, 0x16, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, - 0x65, 0x64, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x12, 0x6f, 0x0a, 0x1b, 0x63, 0x65, 0x72, 0x74, - 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x64, 0x5f, - 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, - 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, - 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x43, 0x6f, - 0x6d, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x64, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x52, 0x19, - 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x74, - 0x65, 0x64, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x22, 0x62, 0x0a, 0x17, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0c, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x73, 0x65, - 0x71, 0x5f, 0x6e, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x72, - 0x74, 0x53, 0x65, 0x71, 0x4e, 0x72, 0x12, 0x25, 0x0a, 0x0f, 0x65, 0x6e, 0x64, 0x5f, 0x65, 0x78, - 0x63, 0x6c, 0x5f, 0x73, 0x65, 0x71, 0x5f, 0x6e, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x0c, 0x65, 0x6e, 0x64, 0x45, 0x78, 0x63, 0x6c, 0x53, 0x65, 0x71, 0x4e, 0x72, 0x22, 0xfe, 0x01, - 0x0a, 0x18, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x79, - 0x6e, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x14, 0x72, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x73, 0x65, 0x71, 0x5f, - 0x6e, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x11, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x53, 0x74, 0x61, 0x72, 0x74, 0x53, 0x65, 0x71, 0x4e, 0x72, 0x12, 0x34, 0x0a, 0x17, 0x72, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x65, 0x6e, 0x64, 0x5f, 0x65, 0x78, 0x63, 0x6c, 0x5f, - 0x73, 0x65, 0x71, 0x5f, 0x6e, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x13, 0x72, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x45, 0x6e, 0x64, 0x45, 0x78, 0x63, 0x6c, 0x53, 0x65, 0x71, 0x4e, - 0x72, 0x12, 0x7b, 0x0a, 0x20, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x73, 0x74, - 0x61, 0x74, 0x65, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x62, - 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x6f, 0x66, - 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, - 0x5f, 0x31, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x53, 0x74, 0x61, 0x74, 0x65, - 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, - 0x1d, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x53, 0x74, 0x61, 0x74, 0x65, 0x54, 0x72, - 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x22, 0x89, - 0x01, 0x0a, 0x17, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x53, - 0x79, 0x6e, 0x63, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x35, 0x0a, 0x17, 0x6c, 0x6f, - 0x77, 0x65, 0x73, 0x74, 0x5f, 0x70, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x73, - 0x65, 0x71, 0x5f, 0x6e, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x14, 0x6c, 0x6f, 0x77, - 0x65, 0x73, 0x74, 0x50, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x64, 0x53, 0x65, 0x71, 0x4e, - 0x72, 0x12, 0x37, 0x0a, 0x18, 0x68, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x5f, 0x63, 0x6f, 0x6d, - 0x6d, 0x69, 0x74, 0x74, 0x65, 0x64, 0x5f, 0x73, 0x65, 0x71, 0x5f, 0x6e, 0x72, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x15, 0x68, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x6d, 0x6d, - 0x69, 0x74, 0x74, 0x65, 0x64, 0x53, 0x65, 0x71, 0x4e, 0x72, 0x22, 0x80, 0x01, 0x0a, 0x1b, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x72, 0x65, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x43, 0x68, - 0x75, 0x6e, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x09, 0x74, 0x6f, - 0x5f, 0x73, 0x65, 0x71, 0x5f, 0x6e, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x74, - 0x6f, 0x53, 0x65, 0x71, 0x4e, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, - 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x73, 0x74, 0x61, - 0x72, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x24, 0x0a, 0x0e, 0x65, 0x6e, 0x64, 0x5f, 0x69, - 0x6e, 0x63, 0x6c, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x0c, 0x65, 0x6e, 0x64, 0x49, 0x6e, 0x63, 0x6c, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x36, 0x0a, - 0x0c, 0x4b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x50, 0x61, 0x69, 0x72, 0x12, 0x10, 0x0a, - 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, - 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x5a, 0x0a, 0x16, 0x4c, 0x65, 0x61, 0x66, 0x4b, 0x65, 0x79, - 0x41, 0x6e, 0x64, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x12, - 0x1d, 0x0a, 0x0a, 0x6b, 0x65, 0x79, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x09, 0x6b, 0x65, 0x79, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x21, - 0x0a, 0x0c, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x44, 0x69, 0x67, 0x65, 0x73, - 0x74, 0x22, 0x6c, 0x0a, 0x0c, 0x42, 0x6f, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4c, 0x65, 0x61, - 0x66, 0x12, 0x40, 0x0a, 0x04, 0x6c, 0x65, 0x61, 0x66, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x2c, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, - 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x4c, 0x65, 0x61, 0x66, 0x4b, 0x65, 0x79, 0x41, 0x6e, - 0x64, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x52, 0x04, 0x6c, - 0x65, 0x61, 0x66, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x69, 0x62, 0x6c, 0x69, 0x6e, 0x67, 0x73, 0x18, - 0x02, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x08, 0x73, 0x69, 0x62, 0x6c, 0x69, 0x6e, 0x67, 0x73, 0x22, - 0xdf, 0x02, 0x0a, 0x1c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x72, 0x65, 0x65, 0x53, - 0x79, 0x6e, 0x63, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x1a, 0x0a, 0x09, 0x74, 0x6f, 0x5f, 0x73, 0x65, 0x71, 0x5f, 0x6e, 0x72, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x07, 0x74, 0x6f, 0x53, 0x65, 0x71, 0x4e, 0x72, 0x12, 0x1f, 0x0a, 0x0b, - 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x33, 0x0a, - 0x16, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x65, 0x6e, 0x64, 0x5f, 0x69, 0x6e, 0x63, - 0x6c, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x13, 0x72, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x45, 0x6e, 0x64, 0x49, 0x6e, 0x63, 0x6c, 0x49, 0x6e, 0x64, - 0x65, 0x78, 0x12, 0x17, 0x0a, 0x07, 0x67, 0x6f, 0x5f, 0x61, 0x77, 0x61, 0x79, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x06, 0x67, 0x6f, 0x41, 0x77, 0x61, 0x79, 0x12, 0x24, 0x0a, 0x0e, 0x65, - 0x6e, 0x64, 0x5f, 0x69, 0x6e, 0x63, 0x6c, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x65, 0x6e, 0x64, 0x49, 0x6e, 0x63, 0x6c, 0x49, 0x6e, 0x64, 0x65, - 0x78, 0x12, 0x41, 0x0a, 0x0a, 0x6b, 0x65, 0x79, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, - 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, - 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x4b, 0x65, 0x79, - 0x56, 0x61, 0x6c, 0x75, 0x65, 0x50, 0x61, 0x69, 0x72, 0x52, 0x09, 0x6b, 0x65, 0x79, 0x56, 0x61, - 0x6c, 0x75, 0x65, 0x73, 0x12, 0x4b, 0x0a, 0x0f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, - 0x5f, 0x6c, 0x65, 0x61, 0x76, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, - 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, - 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x42, 0x6f, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4c, 0x65, 0x61, - 0x66, 0x52, 0x0e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4c, 0x65, 0x61, 0x76, 0x65, - 0x73, 0x22, 0xe7, 0x01, 0x0a, 0x0f, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x53, 0x74, 0x61, 0x72, 0x74, - 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x5b, 0x0a, 0x11, 0x68, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, - 0x5f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x2e, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, - 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, - 0x64, 0x50, 0x72, 0x65, 0x70, 0x61, 0x72, 0x65, 0x4f, 0x72, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, - 0x52, 0x10, 0x68, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, - 0x65, 0x64, 0x12, 0x77, 0x0a, 0x17, 0x68, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x5f, 0x63, 0x65, - 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x02, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, - 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, - 0x62, 0x75, 0x74, 0x65, 0x64, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x48, 0x69, 0x67, 0x68, 0x65, - 0x73, 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x52, 0x15, 0x68, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x43, 0x65, 0x72, - 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x22, 0xb4, 0x01, 0x0a, 0x18, - 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x50, 0x72, 0x65, 0x70, 0x61, 0x72, 0x65, - 0x4f, 0x72, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x12, 0x42, 0x0a, 0x07, 0x70, 0x72, 0x65, 0x70, - 0x61, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x6f, 0x66, 0x66, 0x63, - 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, - 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x50, 0x72, 0x65, 0x70, 0x61, 0x72, - 0x65, 0x48, 0x00, 0x52, 0x07, 0x70, 0x72, 0x65, 0x70, 0x61, 0x72, 0x65, 0x12, 0x3f, 0x0a, 0x06, - 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x6f, - 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, - 0x33, 0x5f, 0x31, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x43, 0x6f, 0x6d, - 0x6d, 0x69, 0x74, 0x48, 0x00, 0x52, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x42, 0x13, 0x0a, - 0x11, 0x70, 0x72, 0x65, 0x70, 0x61, 0x72, 0x65, 0x5f, 0x6f, 0x72, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, - 0x69, 0x74, 0x22, 0xbe, 0x03, 0x0a, 0x10, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, - 0x50, 0x72, 0x65, 0x70, 0x61, 0x72, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x12, 0x15, 0x0a, - 0x06, 0x73, 0x65, 0x71, 0x5f, 0x6e, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x73, - 0x65, 0x71, 0x4e, 0x72, 0x12, 0x43, 0x0a, 0x1e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x72, - 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x5f, - 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x1b, 0x73, 0x74, - 0x61, 0x74, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, - 0x75, 0x74, 0x73, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x66, 0x0a, 0x18, 0x73, 0x74, 0x61, - 0x74, 0x65, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6f, 0x75, - 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x6f, 0x66, - 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, - 0x5f, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, - 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x52, 0x16, 0x73, 0x74, 0x61, 0x74, 0x65, - 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, - 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x5f, - 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x73, 0x74, - 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x34, 0x0a, - 0x16, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x5f, 0x70, 0x6c, 0x75, 0x73, 0x5f, 0x70, 0x72, - 0x65, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x14, 0x72, - 0x65, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x50, 0x6c, 0x75, 0x73, 0x50, 0x72, 0x65, 0x63, 0x75, 0x72, - 0x73, 0x6f, 0x72, 0x12, 0x6e, 0x0a, 0x1a, 0x70, 0x72, 0x65, 0x70, 0x61, 0x72, 0x65, 0x5f, 0x71, - 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, - 0x65, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, - 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x41, - 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x64, 0x50, 0x72, 0x65, 0x70, 0x61, 0x72, 0x65, - 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x18, 0x70, 0x72, 0x65, 0x70, 0x61, - 0x72, 0x65, 0x51, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, - 0x61, 0x74, 0x65, 0x22, 0xba, 0x03, 0x0a, 0x0f, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, - 0x64, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x12, 0x15, 0x0a, - 0x06, 0x73, 0x65, 0x71, 0x5f, 0x6e, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x73, - 0x65, 0x71, 0x4e, 0x72, 0x12, 0x43, 0x0a, 0x1e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x72, - 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x5f, - 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x1b, 0x73, 0x74, - 0x61, 0x74, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, - 0x75, 0x74, 0x73, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x66, 0x0a, 0x18, 0x73, 0x74, 0x61, - 0x74, 0x65, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6f, 0x75, - 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x6f, 0x66, - 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, - 0x5f, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, - 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x52, 0x16, 0x73, 0x74, 0x61, 0x74, 0x65, - 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, - 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x5f, - 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x73, 0x74, - 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x34, 0x0a, - 0x16, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x5f, 0x70, 0x6c, 0x75, 0x73, 0x5f, 0x70, 0x72, - 0x65, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x14, 0x72, - 0x65, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x50, 0x6c, 0x75, 0x73, 0x50, 0x72, 0x65, 0x63, 0x75, 0x72, - 0x73, 0x6f, 0x72, 0x12, 0x6b, 0x0a, 0x19, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x5f, 0x71, 0x75, - 0x6f, 0x72, 0x75, 0x6d, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, - 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, - 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x41, 0x74, - 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x64, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x53, 0x69, - 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x17, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x51, - 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, - 0x22, 0xae, 0x03, 0x0a, 0x19, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x43, 0x6f, - 0x6d, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x64, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x12, 0x21, - 0x0a, 0x0c, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x5f, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x45, 0x70, 0x6f, 0x63, - 0x68, 0x12, 0x15, 0x0a, 0x06, 0x73, 0x65, 0x71, 0x5f, 0x6e, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x05, 0x73, 0x65, 0x71, 0x4e, 0x72, 0x12, 0x43, 0x0a, 0x1e, 0x73, 0x74, 0x61, 0x74, - 0x65, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x6e, 0x70, - 0x75, 0x74, 0x73, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x1b, 0x73, 0x74, 0x61, 0x74, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, - 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x43, 0x0a, - 0x1e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, - 0x6e, 0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x1b, 0x73, 0x74, 0x61, 0x74, 0x65, 0x54, 0x72, 0x61, 0x6e, - 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x44, 0x69, 0x67, 0x65, - 0x73, 0x74, 0x12, 0x2a, 0x0a, 0x11, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x72, 0x6f, 0x6f, 0x74, - 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x73, - 0x74, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x34, - 0x0a, 0x16, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x5f, 0x70, 0x6c, 0x75, 0x73, 0x5f, 0x70, - 0x72, 0x65, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x14, - 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x50, 0x6c, 0x75, 0x73, 0x50, 0x72, 0x65, 0x63, 0x75, - 0x72, 0x73, 0x6f, 0x72, 0x12, 0x6b, 0x0a, 0x19, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x5f, 0x71, - 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, - 0x65, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, - 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x41, - 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x64, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x53, - 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x17, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, - 0x51, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, - 0x65, 0x22, 0x80, 0x01, 0x0a, 0x19, 0x48, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x43, 0x65, 0x72, - 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, - 0x15, 0x0a, 0x06, 0x73, 0x65, 0x71, 0x5f, 0x6e, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x05, 0x73, 0x65, 0x71, 0x4e, 0x72, 0x12, 0x36, 0x0a, 0x17, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, - 0x74, 0x65, 0x64, 0x5f, 0x65, 0x6c, 0x73, 0x65, 0x5f, 0x70, 0x72, 0x65, 0x70, 0x61, 0x72, 0x65, - 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x74, - 0x65, 0x64, 0x45, 0x6c, 0x73, 0x65, 0x50, 0x72, 0x65, 0x70, 0x61, 0x72, 0x65, 0x64, 0x12, 0x14, - 0x0a, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x65, - 0x70, 0x6f, 0x63, 0x68, 0x22, 0xc8, 0x01, 0x0a, 0x29, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, - 0x74, 0x65, 0x64, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x48, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, + 0x70, 0x52, 0x1f, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x48, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x12, 0x82, 0x01, 0x0a, 0x22, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x68, 0x69, - 0x67, 0x68, 0x65, 0x73, 0x74, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, - 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x35, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, - 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x48, 0x69, 0x67, - 0x68, 0x65, 0x73, 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x54, 0x69, 0x6d, - 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x1f, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x48, 0x69, - 0x67, 0x68, 0x65, 0x73, 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x54, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, - 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x22, - 0xb0, 0x01, 0x0a, 0x1f, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x48, 0x69, 0x67, 0x68, 0x65, 0x73, - 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x12, 0x6f, 0x0a, 0x1b, 0x68, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x5f, 0x63, - 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, - 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, - 0x48, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, - 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x19, 0x68, 0x69, 0x67, 0x68, 0x65, - 0x73, 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, - 0x72, 0x65, 0x22, 0x55, 0x0a, 0x15, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x64, - 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x6f, - 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x0b, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, - 0x08, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, - 0x08, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x22, 0x91, 0x01, 0x0a, 0x1b, 0x41, 0x74, - 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x64, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x4f, 0x62, - 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x56, 0x0a, 0x12, 0x73, 0x69, 0x67, + 0x6d, 0x70, 0x22, 0x98, 0x01, 0x0a, 0x11, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x45, 0x70, + 0x6f, 0x63, 0x68, 0x53, 0x74, 0x61, 0x72, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x70, 0x6f, 0x63, + 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x12, 0x51, + 0x0a, 0x11, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x70, 0x72, + 0x6f, 0x6f, 0x66, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x6f, 0x66, 0x66, 0x63, + 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, + 0x2e, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x53, 0x74, 0x61, 0x72, 0x74, 0x50, 0x72, 0x6f, 0x6f, 0x66, + 0x52, 0x0f, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x53, 0x74, 0x61, 0x72, 0x74, 0x50, 0x72, 0x6f, 0x6f, + 0x66, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x62, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x08, 0x61, 0x62, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x22, 0x56, 0x0a, + 0x11, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x53, 0x74, 0x61, + 0x72, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x12, 0x15, 0x0a, 0x06, 0x73, 0x65, 0x71, 0x5f, + 0x6e, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x73, 0x65, 0x71, 0x4e, 0x72, 0x12, + 0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, + 0x71, 0x75, 0x65, 0x72, 0x79, 0x22, 0x99, 0x01, 0x0a, 0x12, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, + 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x65, 0x70, 0x6f, + 0x63, 0x68, 0x12, 0x15, 0x0a, 0x06, 0x73, 0x65, 0x71, 0x5f, 0x6e, 0x72, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x05, 0x73, 0x65, 0x71, 0x4e, 0x72, 0x12, 0x56, 0x0a, 0x12, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, + 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x11, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0d, 0x52, 0x08, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x22, 0x53, 0x0a, - 0x11, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, - 0x72, 0x65, 0x22, 0x52, 0x0a, 0x1a, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x64, - 0x50, 0x72, 0x65, 0x70, 0x61, 0x72, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, - 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x16, - 0x0a, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, - 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x22, 0x51, 0x0a, 0x19, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, - 0x75, 0x74, 0x65, 0x64, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, - 0x75, 0x72, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, - 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0d, 0x52, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x22, 0xe6, 0x01, 0x0a, 0x1c, 0x41, 0x74, - 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, 0x53, 0x74, 0x61, 0x74, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, - 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x60, 0x0a, 0x16, 0x73, 0x74, - 0x61, 0x74, 0x65, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x62, - 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x6f, 0x66, 0x66, + 0x6e, 0x22, 0xb7, 0x01, 0x0a, 0x0f, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x50, 0x72, 0x6f, + 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x12, 0x15, 0x0a, 0x06, 0x73, + 0x65, 0x71, 0x5f, 0x6e, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x73, 0x65, 0x71, + 0x4e, 0x72, 0x12, 0x77, 0x0a, 0x1e, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x64, + 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, - 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, - 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x14, 0x73, 0x74, 0x61, 0x74, 0x65, 0x54, 0x72, 0x61, - 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x64, 0x0a, 0x15, - 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x64, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, - 0x74, 0x75, 0x72, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x6f, 0x66, - 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, - 0x5f, 0x31, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x64, 0x43, 0x6f, 0x6d, - 0x6d, 0x69, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x14, 0x61, 0x74, - 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x64, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, - 0x65, 0x73, 0x22, 0xd2, 0x02, 0x0a, 0x14, 0x53, 0x74, 0x61, 0x74, 0x65, 0x54, 0x72, 0x61, 0x6e, - 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x14, 0x0a, 0x05, 0x65, - 0x70, 0x6f, 0x63, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x65, 0x70, 0x6f, 0x63, - 0x68, 0x12, 0x15, 0x0a, 0x06, 0x73, 0x65, 0x71, 0x5f, 0x6e, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x05, 0x73, 0x65, 0x71, 0x4e, 0x72, 0x12, 0x43, 0x0a, 0x1e, 0x73, 0x74, 0x61, 0x74, - 0x65, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x6e, 0x70, - 0x75, 0x74, 0x73, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x1b, 0x73, 0x74, 0x61, 0x74, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, - 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x66, 0x0a, - 0x18, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, - 0x6e, 0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x2c, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, - 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x54, 0x72, 0x61, 0x6e, - 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x52, 0x16, 0x73, - 0x74, 0x61, 0x74, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, - 0x74, 0x70, 0x75, 0x74, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x72, - 0x6f, 0x6f, 0x74, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x0f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x44, 0x69, 0x67, 0x65, 0x73, - 0x74, 0x12, 0x34, 0x0a, 0x16, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x5f, 0x70, 0x6c, 0x75, - 0x73, 0x5f, 0x70, 0x72, 0x65, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x14, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x50, 0x6c, 0x75, 0x73, 0x50, 0x72, - 0x65, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x22, 0x61, 0x0a, 0x16, 0x53, 0x74, 0x61, 0x74, 0x65, + 0x31, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x64, 0x53, 0x69, 0x67, 0x6e, + 0x65, 0x64, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x1c, 0x61, + 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x64, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x4f, + 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x5b, 0x0a, 0x0e, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x50, 0x72, 0x65, 0x70, 0x61, 0x72, 0x65, 0x12, 0x14, 0x0a, + 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x65, 0x70, + 0x6f, 0x63, 0x68, 0x12, 0x15, 0x0a, 0x06, 0x73, 0x65, 0x71, 0x5f, 0x6e, 0x72, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x05, 0x73, 0x65, 0x71, 0x4e, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, + 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, + 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x5a, 0x0a, 0x0d, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x70, 0x6f, + 0x63, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x12, + 0x15, 0x0a, 0x06, 0x73, 0x65, 0x71, 0x5f, 0x6e, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x05, 0x73, 0x65, 0x71, 0x4e, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, + 0x75, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, + 0x74, 0x75, 0x72, 0x65, 0x22, 0xa0, 0x01, 0x0a, 0x17, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, + 0x12, 0x15, 0x0a, 0x06, 0x73, 0x65, 0x71, 0x5f, 0x6e, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x05, 0x73, 0x65, 0x71, 0x4e, 0x72, 0x12, 0x2b, 0x0a, 0x11, 0x72, 0x65, 0x70, 0x6f, 0x72, + 0x74, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, + 0x28, 0x0c, 0x52, 0x10, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, + 0x75, 0x72, 0x65, 0x73, 0x12, 0x41, 0x0a, 0x1d, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x5f, + 0x70, 0x6c, 0x75, 0x73, 0x5f, 0x70, 0x72, 0x65, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x5f, 0x64, + 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x1a, 0x72, 0x65, 0x70, + 0x6f, 0x72, 0x74, 0x73, 0x50, 0x6c, 0x75, 0x73, 0x50, 0x72, 0x65, 0x63, 0x75, 0x72, 0x73, 0x6f, + 0x72, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x22, 0x3b, 0x0a, 0x22, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x50, 0x6c, 0x75, 0x73, 0x50, 0x72, 0x65, + 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, + 0x06, 0x73, 0x65, 0x71, 0x5f, 0x6e, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x73, + 0x65, 0x71, 0x4e, 0x72, 0x22, 0x6a, 0x0a, 0x1b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, + 0x65, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x50, 0x6c, 0x75, 0x73, 0x50, 0x72, 0x65, 0x63, 0x75, 0x72, + 0x73, 0x6f, 0x72, 0x12, 0x15, 0x0a, 0x06, 0x73, 0x65, 0x71, 0x5f, 0x6e, 0x72, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x05, 0x73, 0x65, 0x71, 0x4e, 0x72, 0x12, 0x34, 0x0a, 0x16, 0x72, 0x65, + 0x70, 0x6f, 0x72, 0x74, 0x73, 0x5f, 0x70, 0x6c, 0x75, 0x73, 0x5f, 0x70, 0x72, 0x65, 0x63, 0x75, + 0x72, 0x73, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x14, 0x72, 0x65, 0x70, 0x6f, + 0x72, 0x74, 0x73, 0x50, 0x6c, 0x75, 0x73, 0x50, 0x72, 0x65, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, + 0x22, 0x62, 0x0a, 0x17, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0c, 0x73, + 0x74, 0x61, 0x72, 0x74, 0x5f, 0x73, 0x65, 0x71, 0x5f, 0x6e, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x53, 0x65, 0x71, 0x4e, 0x72, 0x12, 0x25, 0x0a, + 0x0f, 0x65, 0x6e, 0x64, 0x5f, 0x65, 0x78, 0x63, 0x6c, 0x5f, 0x73, 0x65, 0x71, 0x5f, 0x6e, 0x72, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x65, 0x6e, 0x64, 0x45, 0x78, 0x63, 0x6c, 0x53, + 0x65, 0x71, 0x4e, 0x72, 0x22, 0xfe, 0x01, 0x0a, 0x18, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x2f, 0x0a, 0x14, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x73, 0x74, 0x61, + 0x72, 0x74, 0x5f, 0x73, 0x65, 0x71, 0x5f, 0x6e, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x11, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x74, 0x61, 0x72, 0x74, 0x53, 0x65, 0x71, + 0x4e, 0x72, 0x12, 0x34, 0x0a, 0x17, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x65, 0x6e, + 0x64, 0x5f, 0x65, 0x78, 0x63, 0x6c, 0x5f, 0x73, 0x65, 0x71, 0x5f, 0x6e, 0x72, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x13, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x45, 0x6e, 0x64, 0x45, + 0x78, 0x63, 0x6c, 0x53, 0x65, 0x71, 0x4e, 0x72, 0x12, 0x7b, 0x0a, 0x20, 0x61, 0x74, 0x74, 0x65, + 0x73, 0x74, 0x65, 0x64, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x03, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, + 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, + 0x65, 0x64, 0x53, 0x74, 0x61, 0x74, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x1d, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x65, 0x64, + 0x53, 0x74, 0x61, 0x74, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x22, 0x89, 0x01, 0x0a, 0x17, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, + 0x79, 0x12, 0x35, 0x0a, 0x17, 0x6c, 0x6f, 0x77, 0x65, 0x73, 0x74, 0x5f, 0x70, 0x65, 0x72, 0x73, + 0x69, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x73, 0x65, 0x71, 0x5f, 0x6e, 0x72, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x14, 0x6c, 0x6f, 0x77, 0x65, 0x73, 0x74, 0x50, 0x65, 0x72, 0x73, 0x69, 0x73, + 0x74, 0x65, 0x64, 0x53, 0x65, 0x71, 0x4e, 0x72, 0x12, 0x37, 0x0a, 0x18, 0x68, 0x69, 0x67, 0x68, + 0x65, 0x73, 0x74, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x64, 0x5f, 0x73, 0x65, + 0x71, 0x5f, 0x6e, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x15, 0x68, 0x69, 0x67, 0x68, + 0x65, 0x73, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x64, 0x53, 0x65, 0x71, 0x4e, + 0x72, 0x22, 0x80, 0x01, 0x0a, 0x1b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x54, 0x72, 0x65, + 0x65, 0x53, 0x79, 0x6e, 0x63, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x1a, 0x0a, 0x09, 0x74, 0x6f, 0x5f, 0x73, 0x65, 0x71, 0x5f, 0x6e, 0x72, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x74, 0x6f, 0x53, 0x65, 0x71, 0x4e, 0x72, 0x12, 0x1f, 0x0a, + 0x0b, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x24, + 0x0a, 0x0e, 0x65, 0x6e, 0x64, 0x5f, 0x69, 0x6e, 0x63, 0x6c, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x65, 0x6e, 0x64, 0x49, 0x6e, 0x63, 0x6c, 0x49, + 0x6e, 0x64, 0x65, 0x78, 0x22, 0x36, 0x0a, 0x0c, 0x4b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x50, 0x61, 0x69, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x5a, 0x0a, 0x16, + 0x4c, 0x65, 0x61, 0x66, 0x4b, 0x65, 0x79, 0x41, 0x6e, 0x64, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x44, + 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x6b, 0x65, 0x79, 0x5f, 0x64, 0x69, + 0x67, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x6b, 0x65, 0x79, 0x44, + 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x64, + 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x22, 0x6c, 0x0a, 0x0c, 0x42, 0x6f, 0x75, 0x6e, + 0x64, 0x69, 0x6e, 0x67, 0x4c, 0x65, 0x61, 0x66, 0x12, 0x40, 0x0a, 0x04, 0x6c, 0x65, 0x61, 0x66, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, + 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x4c, 0x65, + 0x61, 0x66, 0x4b, 0x65, 0x79, 0x41, 0x6e, 0x64, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x44, 0x69, 0x67, + 0x65, 0x73, 0x74, 0x73, 0x52, 0x04, 0x6c, 0x65, 0x61, 0x66, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x69, + 0x62, 0x6c, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x08, 0x73, 0x69, + 0x62, 0x6c, 0x69, 0x6e, 0x67, 0x73, 0x22, 0xdf, 0x02, 0x0a, 0x1c, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x54, 0x72, 0x65, 0x65, 0x53, 0x79, 0x6e, 0x63, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x09, 0x74, 0x6f, 0x5f, 0x73, 0x65, + 0x71, 0x5f, 0x6e, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x74, 0x6f, 0x53, 0x65, + 0x71, 0x4e, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x69, 0x6e, 0x64, + 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x49, + 0x6e, 0x64, 0x65, 0x78, 0x12, 0x33, 0x0a, 0x16, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, + 0x65, 0x6e, 0x64, 0x5f, 0x69, 0x6e, 0x63, 0x6c, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x13, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x45, 0x6e, 0x64, + 0x49, 0x6e, 0x63, 0x6c, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x17, 0x0a, 0x07, 0x67, 0x6f, 0x5f, + 0x61, 0x77, 0x61, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x67, 0x6f, 0x41, 0x77, + 0x61, 0x79, 0x12, 0x24, 0x0a, 0x0e, 0x65, 0x6e, 0x64, 0x5f, 0x69, 0x6e, 0x63, 0x6c, 0x5f, 0x69, + 0x6e, 0x64, 0x65, 0x78, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x65, 0x6e, 0x64, 0x49, + 0x6e, 0x63, 0x6c, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x41, 0x0a, 0x0a, 0x6b, 0x65, 0x79, 0x5f, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x6f, + 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, + 0x33, 0x5f, 0x31, 0x2e, 0x4b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x50, 0x61, 0x69, 0x72, + 0x52, 0x09, 0x6b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x4b, 0x0a, 0x0f, 0x62, + 0x6f, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x6c, 0x65, 0x61, 0x76, 0x65, 0x73, 0x18, 0x07, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, + 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x42, 0x6f, 0x75, 0x6e, + 0x64, 0x69, 0x6e, 0x67, 0x4c, 0x65, 0x61, 0x66, 0x52, 0x0e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x69, + 0x6e, 0x67, 0x4c, 0x65, 0x61, 0x76, 0x65, 0x73, 0x22, 0xe7, 0x01, 0x0a, 0x0f, 0x45, 0x70, 0x6f, + 0x63, 0x68, 0x53, 0x74, 0x61, 0x72, 0x74, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x5b, 0x0a, 0x11, + 0x68, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, + 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x43, + 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x50, 0x72, 0x65, 0x70, 0x61, 0x72, 0x65, 0x4f, + 0x72, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x52, 0x10, 0x68, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x12, 0x77, 0x0a, 0x17, 0x68, 0x69, 0x67, + 0x68, 0x65, 0x73, 0x74, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x70, + 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x6f, 0x66, 0x66, + 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, + 0x31, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x64, 0x53, 0x69, 0x67, 0x6e, + 0x65, 0x64, 0x48, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, + 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x15, 0x68, 0x69, 0x67, + 0x68, 0x65, 0x73, 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x50, 0x72, 0x6f, + 0x6f, 0x66, 0x22, 0xb4, 0x01, 0x0a, 0x18, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, + 0x50, 0x72, 0x65, 0x70, 0x61, 0x72, 0x65, 0x4f, 0x72, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x12, + 0x42, 0x0a, 0x07, 0x70, 0x72, 0x65, 0x70, 0x61, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x26, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, + 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, + 0x64, 0x50, 0x72, 0x65, 0x70, 0x61, 0x72, 0x65, 0x48, 0x00, 0x52, 0x07, 0x70, 0x72, 0x65, 0x70, + 0x61, 0x72, 0x65, 0x12, 0x3f, 0x0a, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, + 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, + 0x66, 0x69, 0x65, 0x64, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x48, 0x00, 0x52, 0x06, 0x63, 0x6f, + 0x6d, 0x6d, 0x69, 0x74, 0x42, 0x13, 0x0a, 0x11, 0x70, 0x72, 0x65, 0x70, 0x61, 0x72, 0x65, 0x5f, + 0x6f, 0x72, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x22, 0xaa, 0x03, 0x0a, 0x10, 0x43, 0x65, + 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x50, 0x72, 0x65, 0x70, 0x61, 0x72, 0x65, 0x12, 0x14, + 0x0a, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x65, + 0x70, 0x6f, 0x63, 0x68, 0x12, 0x15, 0x0a, 0x06, 0x73, 0x65, 0x71, 0x5f, 0x6e, 0x72, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x73, 0x65, 0x71, 0x4e, 0x72, 0x12, 0x43, 0x0a, 0x1e, 0x73, + 0x74, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, + 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x1b, 0x73, 0x74, 0x61, 0x74, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, + 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, + 0x12, 0x45, 0x0a, 0x1f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x69, + 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x5f, 0x64, 0x69, 0x67, + 0x65, 0x73, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x1c, 0x73, 0x74, 0x61, 0x74, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, - 0x73, 0x12, 0x47, 0x0a, 0x09, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x73, 0x65, 0x74, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, - 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x4b, 0x65, 0x79, 0x56, - 0x61, 0x6c, 0x75, 0x65, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x08, 0x77, 0x72, 0x69, 0x74, 0x65, 0x53, 0x65, 0x74, 0x22, 0x58, 0x0a, 0x14, 0x4b, 0x65, - 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x64, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x64, 0x22, 0xd6, 0x01, 0x0a, 0x15, 0x53, 0x74, 0x61, 0x74, 0x65, 0x54, 0x72, - 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x15, - 0x0a, 0x06, 0x73, 0x65, 0x71, 0x5f, 0x6e, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, - 0x73, 0x65, 0x71, 0x4e, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x72, - 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x72, 0x6f, 0x75, 0x6e, - 0x64, 0x12, 0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, 0x64, 0x0a, 0x17, 0x61, 0x74, 0x74, 0x72, 0x69, - 0x62, 0x75, 0x74, 0x65, 0x64, 0x5f, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, + 0x73, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x2a, 0x0a, 0x11, 0x73, 0x74, 0x61, 0x74, 0x65, + 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x0f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x44, 0x69, 0x67, + 0x65, 0x73, 0x74, 0x12, 0x41, 0x0a, 0x1d, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x5f, 0x70, + 0x6c, 0x75, 0x73, 0x5f, 0x70, 0x72, 0x65, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x5f, 0x64, 0x69, + 0x67, 0x65, 0x73, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x1a, 0x72, 0x65, 0x70, 0x6f, + 0x72, 0x74, 0x73, 0x50, 0x6c, 0x75, 0x73, 0x50, 0x72, 0x65, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, + 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x6e, 0x0a, 0x1a, 0x70, 0x72, 0x65, 0x70, 0x61, 0x72, + 0x65, 0x5f, 0x71, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x65, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x6f, 0x66, 0x66, + 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, + 0x31, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x64, 0x50, 0x72, 0x65, 0x70, + 0x61, 0x72, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x18, 0x70, 0x72, + 0x65, 0x70, 0x61, 0x72, 0x65, 0x51, 0x75, 0x6f, 0x72, 0x75, 0x6d, 0x43, 0x65, 0x72, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x22, 0xa6, 0x03, 0x0a, 0x0f, 0x43, 0x65, 0x72, 0x74, 0x69, + 0x66, 0x69, 0x65, 0x64, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x70, + 0x6f, 0x63, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, + 0x12, 0x15, 0x0a, 0x06, 0x73, 0x65, 0x71, 0x5f, 0x6e, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x05, 0x73, 0x65, 0x71, 0x4e, 0x72, 0x12, 0x43, 0x0a, 0x1e, 0x73, 0x74, 0x61, 0x74, 0x65, + 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x6e, 0x70, 0x75, + 0x74, 0x73, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x1b, 0x73, 0x74, 0x61, 0x74, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x49, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x45, 0x0a, 0x1f, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x1c, 0x73, 0x74, 0x61, 0x74, 0x65, 0x54, 0x72, 0x61, 0x6e, + 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x44, 0x69, 0x67, + 0x65, 0x73, 0x74, 0x12, 0x2a, 0x0a, 0x11, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x72, 0x6f, 0x6f, + 0x74, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, + 0x41, 0x0a, 0x1d, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x5f, 0x70, 0x6c, 0x75, 0x73, 0x5f, + 0x70, 0x72, 0x65, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x1a, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x50, + 0x6c, 0x75, 0x73, 0x50, 0x72, 0x65, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x44, 0x69, 0x67, 0x65, + 0x73, 0x74, 0x12, 0x6b, 0x0a, 0x19, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x5f, 0x71, 0x75, 0x6f, + 0x72, 0x75, 0x6d, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x18, + 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, + 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x41, 0x74, 0x74, + 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x64, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x53, 0x69, 0x67, + 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x17, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x51, 0x75, + 0x6f, 0x72, 0x75, 0x6d, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x22, + 0x80, 0x01, 0x0a, 0x19, 0x48, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, + 0x66, 0x69, 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x15, 0x0a, + 0x06, 0x73, 0x65, 0x71, 0x5f, 0x6e, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x73, + 0x65, 0x71, 0x4e, 0x72, 0x12, 0x36, 0x0a, 0x17, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x74, 0x65, + 0x64, 0x5f, 0x65, 0x6c, 0x73, 0x65, 0x5f, 0x70, 0x72, 0x65, 0x70, 0x61, 0x72, 0x65, 0x64, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x74, 0x65, 0x64, + 0x45, 0x6c, 0x73, 0x65, 0x50, 0x72, 0x65, 0x70, 0x61, 0x72, 0x65, 0x64, 0x12, 0x14, 0x0a, 0x05, + 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x65, 0x70, 0x6f, + 0x63, 0x68, 0x22, 0xc8, 0x01, 0x0a, 0x29, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, + 0x64, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x48, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x43, 0x65, + 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x12, 0x82, 0x01, 0x0a, 0x22, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x68, 0x69, 0x67, 0x68, + 0x65, 0x73, 0x74, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x74, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, + 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, + 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x48, 0x69, 0x67, 0x68, 0x65, + 0x73, 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x52, 0x1f, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x48, 0x69, 0x67, 0x68, + 0x65, 0x73, 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x22, 0xb0, 0x01, + 0x0a, 0x1f, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x48, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x43, + 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x12, 0x6f, 0x0a, 0x1b, 0x68, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, 0x5f, 0x63, 0x65, 0x72, + 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, + 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x48, 0x69, + 0x67, 0x68, 0x65, 0x73, 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x54, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x19, 0x68, 0x69, 0x67, 0x68, 0x65, 0x73, 0x74, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, + 0x22, 0x55, 0x0a, 0x15, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x64, 0x4f, 0x62, + 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x6f, 0x62, 0x73, + 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, + 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x6f, + 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x6f, + 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x22, 0x91, 0x01, 0x0a, 0x1b, 0x41, 0x74, 0x74, 0x72, + 0x69, 0x62, 0x75, 0x74, 0x65, 0x64, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x4f, 0x62, 0x73, 0x65, + 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x56, 0x0a, 0x12, 0x73, 0x69, 0x67, 0x6e, 0x65, + 0x64, 0x5f, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, + 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x65, + 0x64, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x11, 0x73, 0x69, + 0x67, 0x6e, 0x65, 0x64, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x1a, 0x0a, 0x08, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x08, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x22, 0x53, 0x0a, 0x11, 0x53, + 0x69, 0x67, 0x6e, 0x65, 0x64, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x20, 0x0a, 0x0b, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, + 0x22, 0x52, 0x0a, 0x1a, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x64, 0x50, 0x72, + 0x65, 0x70, 0x61, 0x72, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x1c, + 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x16, 0x0a, 0x06, + 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x73, 0x69, + 0x67, 0x6e, 0x65, 0x72, 0x22, 0x51, 0x0a, 0x19, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, + 0x65, 0x64, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, + 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, + 0x16, 0x0a, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x22, 0xe6, 0x01, 0x0a, 0x1c, 0x41, 0x74, 0x74, 0x65, + 0x73, 0x74, 0x65, 0x64, 0x53, 0x74, 0x61, 0x74, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, + 0x69, 0x6f, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x60, 0x0a, 0x16, 0x73, 0x74, 0x61, 0x74, + 0x65, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x62, 0x6c, 0x6f, + 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, - 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x64, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x16, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, - 0x64, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x82, 0x01, - 0x0a, 0x10, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x6c, 0x6f, 0x62, 0x4f, 0x66, 0x66, - 0x65, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x5f, 0x64, 0x69, 0x67, 0x65, - 0x73, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0c, 0x63, 0x68, 0x75, 0x6e, 0x6b, - 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x61, 0x79, 0x6c, 0x6f, - 0x61, 0x64, 0x5f, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x0d, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x12, 0x22, - 0x0a, 0x0d, 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, 0x5f, 0x73, 0x65, 0x71, 0x5f, 0x6e, 0x72, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, 0x53, 0x65, 0x71, - 0x4e, 0x72, 0x22, 0x5b, 0x0a, 0x17, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x6c, 0x6f, - 0x62, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, - 0x0b, 0x62, 0x6c, 0x6f, 0x62, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x0a, 0x62, 0x6c, 0x6f, 0x62, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x1f, - 0x0a, 0x0b, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x0a, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x22, - 0x8b, 0x01, 0x0a, 0x18, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x6c, 0x6f, 0x62, 0x43, - 0x68, 0x75, 0x6e, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, - 0x62, 0x6c, 0x6f, 0x62, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x0a, 0x62, 0x6c, 0x6f, 0x62, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, - 0x0b, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x0a, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x17, - 0x0a, 0x07, 0x67, 0x6f, 0x5f, 0x61, 0x77, 0x61, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x06, 0x67, 0x6f, 0x41, 0x77, 0x61, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x68, 0x75, 0x6e, 0x6b, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x22, 0x7c, 0x0a, - 0x18, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x6c, 0x6f, 0x62, 0x4f, 0x66, 0x66, 0x65, - 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x62, 0x6c, 0x6f, - 0x62, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, - 0x62, 0x6c, 0x6f, 0x62, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x72, 0x65, - 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6f, 0x66, 0x66, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x0b, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x4f, 0x66, 0x66, 0x65, 0x72, 0x12, 0x1c, 0x0a, - 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x42, 0x11, 0x5a, 0x0f, 0x2e, - 0x3b, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x62, 0x06, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x53, 0x74, 0x61, 0x74, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x14, 0x73, 0x74, 0x61, 0x74, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x64, 0x0a, 0x15, 0x61, 0x74, + 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x64, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, + 0x72, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x6f, 0x66, 0x66, 0x63, + 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, + 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x64, 0x43, 0x6f, 0x6d, 0x6d, 0x69, + 0x74, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x14, 0x61, 0x74, 0x74, 0x72, + 0x69, 0x62, 0x75, 0x74, 0x65, 0x64, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, + 0x22, 0xdf, 0x02, 0x0a, 0x14, 0x53, 0x74, 0x61, 0x74, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, + 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x70, 0x6f, + 0x63, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x12, + 0x15, 0x0a, 0x06, 0x73, 0x65, 0x71, 0x5f, 0x6e, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x05, 0x73, 0x65, 0x71, 0x4e, 0x72, 0x12, 0x43, 0x0a, 0x1e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, + 0x74, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, + 0x73, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x1b, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, + 0x6e, 0x70, 0x75, 0x74, 0x73, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x66, 0x0a, 0x18, 0x73, + 0x74, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, + 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, + 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, + 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, + 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x52, 0x16, 0x73, 0x74, 0x61, + 0x74, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, + 0x75, 0x74, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x72, 0x6f, 0x6f, + 0x74, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, + 0x41, 0x0a, 0x1d, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x5f, 0x70, 0x6c, 0x75, 0x73, 0x5f, + 0x70, 0x72, 0x65, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x1a, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x50, + 0x6c, 0x75, 0x73, 0x50, 0x72, 0x65, 0x63, 0x75, 0x72, 0x73, 0x6f, 0x72, 0x44, 0x69, 0x67, 0x65, + 0x73, 0x74, 0x22, 0x61, 0x0a, 0x16, 0x53, 0x74, 0x61, 0x74, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x12, 0x47, 0x0a, 0x09, + 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x73, 0x65, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x2a, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, + 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x4b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4d, + 0x6f, 0x64, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x77, 0x72, 0x69, + 0x74, 0x65, 0x53, 0x65, 0x74, 0x22, 0x58, 0x0a, 0x14, 0x4b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x10, 0x0a, + 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, + 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x22, + 0xd6, 0x01, 0x0a, 0x15, 0x53, 0x74, 0x61, 0x74, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, + 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x15, 0x0a, 0x06, 0x73, 0x65, 0x71, + 0x5f, 0x6e, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x73, 0x65, 0x71, 0x4e, 0x72, + 0x12, 0x14, 0x0a, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x14, 0x0a, 0x05, + 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x71, 0x75, 0x65, + 0x72, 0x79, 0x12, 0x64, 0x0a, 0x17, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x64, + 0x5f, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x05, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x6f, 0x66, 0x66, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x72, 0x65, + 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x33, 0x5f, 0x31, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, + 0x62, 0x75, 0x74, 0x65, 0x64, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x16, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x64, 0x4f, 0x62, 0x73, 0x65, + 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x8b, 0x01, 0x0a, 0x10, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x42, 0x6c, 0x6f, 0x62, 0x4f, 0x66, 0x66, 0x65, 0x72, 0x12, 0x2c, 0x0a, + 0x12, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x5f, 0x72, + 0x6f, 0x6f, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, 0x63, 0x68, 0x75, 0x6e, 0x6b, + 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x73, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x70, + 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x0d, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x4c, 0x65, 0x6e, 0x67, + 0x74, 0x68, 0x12, 0x22, 0x0a, 0x0d, 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, 0x5f, 0x73, 0x65, 0x71, + 0x5f, 0x6e, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x65, 0x78, 0x70, 0x69, 0x72, + 0x79, 0x53, 0x65, 0x71, 0x4e, 0x72, 0x22, 0x5b, 0x0a, 0x17, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x42, 0x6c, 0x6f, 0x62, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x62, 0x6c, 0x6f, 0x62, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x62, 0x6c, 0x6f, 0x62, 0x44, 0x69, 0x67, 0x65, + 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x5f, 0x69, 0x6e, 0x64, 0x65, + 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x49, 0x6e, + 0x64, 0x65, 0x78, 0x22, 0xa1, 0x01, 0x0a, 0x18, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, + 0x6c, 0x6f, 0x62, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x1f, 0x0a, 0x0b, 0x62, 0x6c, 0x6f, 0x62, 0x5f, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x62, 0x6c, 0x6f, 0x62, 0x44, 0x69, 0x67, 0x65, 0x73, + 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x49, 0x6e, 0x64, + 0x65, 0x78, 0x12, 0x17, 0x0a, 0x07, 0x67, 0x6f, 0x5f, 0x61, 0x77, 0x61, 0x79, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x06, 0x67, 0x6f, 0x41, 0x77, 0x61, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x63, + 0x68, 0x75, 0x6e, 0x6b, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x63, 0x68, 0x75, 0x6e, + 0x6b, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0c, + 0x52, 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x22, 0x7c, 0x0a, 0x18, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x42, 0x6c, 0x6f, 0x62, 0x4f, 0x66, 0x66, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x62, 0x6c, 0x6f, 0x62, 0x5f, 0x64, 0x69, 0x67, 0x65, + 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x62, 0x6c, 0x6f, 0x62, 0x44, 0x69, + 0x67, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x6f, + 0x66, 0x66, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x72, 0x65, 0x6a, 0x65, + 0x63, 0x74, 0x4f, 0x66, 0x66, 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, + 0x74, 0x75, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, + 0x61, 0x74, 0x75, 0x72, 0x65, 0x42, 0x11, 0x5a, 0x0f, 0x2e, 0x3b, 0x73, 0x65, 0x72, 0x69, 0x61, + 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -3511,7 +3427,7 @@ func file_offchainreporting3_1_messages_proto_rawDescGZIP() []byte { return file_offchainreporting3_1_messages_proto_rawDescData } -var file_offchainreporting3_1_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 42) +var file_offchainreporting3_1_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 41) var file_offchainreporting3_1_messages_proto_goTypes = []interface{}{ (*MessageWrapper)(nil), // 0: offchainreporting3_1.MessageWrapper (*MessageNewEpochWish)(nil), // 1: offchainreporting3_1.MessageNewEpochWish @@ -3523,8 +3439,8 @@ var file_offchainreporting3_1_messages_proto_goTypes = []interface{}{ (*MessagePrepare)(nil), // 7: offchainreporting3_1.MessagePrepare (*MessageCommit)(nil), // 8: offchainreporting3_1.MessageCommit (*MessageReportSignatures)(nil), // 9: offchainreporting3_1.MessageReportSignatures - (*MessageCertifiedCommitRequest)(nil), // 10: offchainreporting3_1.MessageCertifiedCommitRequest - (*MessageCertifiedCommit)(nil), // 11: offchainreporting3_1.MessageCertifiedCommit + (*MessageReportsPlusPrecursorRequest)(nil), // 10: offchainreporting3_1.MessageReportsPlusPrecursorRequest + (*MessageReportsPlusPrecursor)(nil), // 11: offchainreporting3_1.MessageReportsPlusPrecursor (*MessageBlockSyncRequest)(nil), // 12: offchainreporting3_1.MessageBlockSyncRequest (*MessageBlockSyncResponse)(nil), // 13: offchainreporting3_1.MessageBlockSyncResponse (*MessageStateSyncSummary)(nil), // 14: offchainreporting3_1.MessageStateSyncSummary @@ -3537,24 +3453,23 @@ var file_offchainreporting3_1_messages_proto_goTypes = []interface{}{ (*CertifiedPrepareOrCommit)(nil), // 21: offchainreporting3_1.CertifiedPrepareOrCommit (*CertifiedPrepare)(nil), // 22: offchainreporting3_1.CertifiedPrepare (*CertifiedCommit)(nil), // 23: offchainreporting3_1.CertifiedCommit - (*CertifiedCommittedReports)(nil), // 24: offchainreporting3_1.CertifiedCommittedReports - (*HighestCertifiedTimestamp)(nil), // 25: offchainreporting3_1.HighestCertifiedTimestamp - (*AttributedSignedHighestCertifiedTimestamp)(nil), // 26: offchainreporting3_1.AttributedSignedHighestCertifiedTimestamp - (*SignedHighestCertifiedTimestamp)(nil), // 27: offchainreporting3_1.SignedHighestCertifiedTimestamp - (*AttributedObservation)(nil), // 28: offchainreporting3_1.AttributedObservation - (*AttributedSignedObservation)(nil), // 29: offchainreporting3_1.AttributedSignedObservation - (*SignedObservation)(nil), // 30: offchainreporting3_1.SignedObservation - (*AttributedPrepareSignature)(nil), // 31: offchainreporting3_1.AttributedPrepareSignature - (*AttributedCommitSignature)(nil), // 32: offchainreporting3_1.AttributedCommitSignature - (*AttestedStateTransitionBlock)(nil), // 33: offchainreporting3_1.AttestedStateTransitionBlock - (*StateTransitionBlock)(nil), // 34: offchainreporting3_1.StateTransitionBlock - (*StateTransitionOutputs)(nil), // 35: offchainreporting3_1.StateTransitionOutputs - (*KeyValueModification)(nil), // 36: offchainreporting3_1.KeyValueModification - (*StateTransitionInputs)(nil), // 37: offchainreporting3_1.StateTransitionInputs - (*MessageBlobOffer)(nil), // 38: offchainreporting3_1.MessageBlobOffer - (*MessageBlobChunkRequest)(nil), // 39: offchainreporting3_1.MessageBlobChunkRequest - (*MessageBlobChunkResponse)(nil), // 40: offchainreporting3_1.MessageBlobChunkResponse - (*MessageBlobOfferResponse)(nil), // 41: offchainreporting3_1.MessageBlobOfferResponse + (*HighestCertifiedTimestamp)(nil), // 24: offchainreporting3_1.HighestCertifiedTimestamp + (*AttributedSignedHighestCertifiedTimestamp)(nil), // 25: offchainreporting3_1.AttributedSignedHighestCertifiedTimestamp + (*SignedHighestCertifiedTimestamp)(nil), // 26: offchainreporting3_1.SignedHighestCertifiedTimestamp + (*AttributedObservation)(nil), // 27: offchainreporting3_1.AttributedObservation + (*AttributedSignedObservation)(nil), // 28: offchainreporting3_1.AttributedSignedObservation + (*SignedObservation)(nil), // 29: offchainreporting3_1.SignedObservation + (*AttributedPrepareSignature)(nil), // 30: offchainreporting3_1.AttributedPrepareSignature + (*AttributedCommitSignature)(nil), // 31: offchainreporting3_1.AttributedCommitSignature + (*AttestedStateTransitionBlock)(nil), // 32: offchainreporting3_1.AttestedStateTransitionBlock + (*StateTransitionBlock)(nil), // 33: offchainreporting3_1.StateTransitionBlock + (*StateTransitionOutputs)(nil), // 34: offchainreporting3_1.StateTransitionOutputs + (*KeyValueModification)(nil), // 35: offchainreporting3_1.KeyValueModification + (*StateTransitionInputs)(nil), // 36: offchainreporting3_1.StateTransitionInputs + (*MessageBlobOffer)(nil), // 37: offchainreporting3_1.MessageBlobOffer + (*MessageBlobChunkRequest)(nil), // 38: offchainreporting3_1.MessageBlobChunkRequest + (*MessageBlobChunkResponse)(nil), // 39: offchainreporting3_1.MessageBlobChunkResponse + (*MessageBlobOfferResponse)(nil), // 40: offchainreporting3_1.MessageBlobOfferResponse } var file_offchainreporting3_1_messages_proto_depIdxs = []int32{ 1, // 0: offchainreporting3_1.MessageWrapper.message_new_epoch_wish:type_name -> offchainreporting3_1.MessageNewEpochWish @@ -3566,49 +3481,45 @@ var file_offchainreporting3_1_messages_proto_depIdxs = []int32{ 7, // 6: offchainreporting3_1.MessageWrapper.message_prepare:type_name -> offchainreporting3_1.MessagePrepare 8, // 7: offchainreporting3_1.MessageWrapper.message_commit:type_name -> offchainreporting3_1.MessageCommit 9, // 8: offchainreporting3_1.MessageWrapper.message_report_signatures:type_name -> offchainreporting3_1.MessageReportSignatures - 10, // 9: offchainreporting3_1.MessageWrapper.message_certified_commit_request:type_name -> offchainreporting3_1.MessageCertifiedCommitRequest - 11, // 10: offchainreporting3_1.MessageWrapper.message_certified_commit:type_name -> offchainreporting3_1.MessageCertifiedCommit + 10, // 9: offchainreporting3_1.MessageWrapper.message_reports_plus_precursor_request:type_name -> offchainreporting3_1.MessageReportsPlusPrecursorRequest + 11, // 10: offchainreporting3_1.MessageWrapper.message_reports_plus_precursor:type_name -> offchainreporting3_1.MessageReportsPlusPrecursor 12, // 11: offchainreporting3_1.MessageWrapper.message_block_sync_request:type_name -> offchainreporting3_1.MessageBlockSyncRequest 13, // 12: offchainreporting3_1.MessageWrapper.message_block_sync_response:type_name -> offchainreporting3_1.MessageBlockSyncResponse 14, // 13: offchainreporting3_1.MessageWrapper.message_state_sync_summary:type_name -> offchainreporting3_1.MessageStateSyncSummary 15, // 14: offchainreporting3_1.MessageWrapper.message_tree_sync_chunk_request:type_name -> offchainreporting3_1.MessageTreeSyncChunkRequest 19, // 15: offchainreporting3_1.MessageWrapper.message_tree_sync_chunk_response:type_name -> offchainreporting3_1.MessageTreeSyncChunkResponse - 38, // 16: offchainreporting3_1.MessageWrapper.message_blob_offer:type_name -> offchainreporting3_1.MessageBlobOffer - 41, // 17: offchainreporting3_1.MessageWrapper.message_blob_offer_response:type_name -> offchainreporting3_1.MessageBlobOfferResponse - 39, // 18: offchainreporting3_1.MessageWrapper.message_blob_chunk_request:type_name -> offchainreporting3_1.MessageBlobChunkRequest - 40, // 19: offchainreporting3_1.MessageWrapper.message_blob_chunk_response:type_name -> offchainreporting3_1.MessageBlobChunkResponse + 37, // 16: offchainreporting3_1.MessageWrapper.message_blob_offer:type_name -> offchainreporting3_1.MessageBlobOffer + 40, // 17: offchainreporting3_1.MessageWrapper.message_blob_offer_response:type_name -> offchainreporting3_1.MessageBlobOfferResponse + 38, // 18: offchainreporting3_1.MessageWrapper.message_blob_chunk_request:type_name -> offchainreporting3_1.MessageBlobChunkRequest + 39, // 19: offchainreporting3_1.MessageWrapper.message_blob_chunk_response:type_name -> offchainreporting3_1.MessageBlobChunkResponse 21, // 20: offchainreporting3_1.MessageEpochStartRequest.highest_certified:type_name -> offchainreporting3_1.CertifiedPrepareOrCommit - 27, // 21: offchainreporting3_1.MessageEpochStartRequest.signed_highest_certified_timestamp:type_name -> offchainreporting3_1.SignedHighestCertifiedTimestamp + 26, // 21: offchainreporting3_1.MessageEpochStartRequest.signed_highest_certified_timestamp:type_name -> offchainreporting3_1.SignedHighestCertifiedTimestamp 20, // 22: offchainreporting3_1.MessageEpochStart.epoch_start_proof:type_name -> offchainreporting3_1.EpochStartProof - 30, // 23: offchainreporting3_1.MessageObservation.signed_observation:type_name -> offchainreporting3_1.SignedObservation - 29, // 24: offchainreporting3_1.MessageProposal.attributed_signed_observations:type_name -> offchainreporting3_1.AttributedSignedObservation - 24, // 25: offchainreporting3_1.MessageCertifiedCommit.certified_committed_reports:type_name -> offchainreporting3_1.CertifiedCommittedReports - 33, // 26: offchainreporting3_1.MessageBlockSyncResponse.attested_state_transition_blocks:type_name -> offchainreporting3_1.AttestedStateTransitionBlock - 17, // 27: offchainreporting3_1.BoundingLeaf.leaf:type_name -> offchainreporting3_1.LeafKeyAndValueDigests - 16, // 28: offchainreporting3_1.MessageTreeSyncChunkResponse.key_values:type_name -> offchainreporting3_1.KeyValuePair - 18, // 29: offchainreporting3_1.MessageTreeSyncChunkResponse.bounding_leaves:type_name -> offchainreporting3_1.BoundingLeaf - 21, // 30: offchainreporting3_1.EpochStartProof.highest_certified:type_name -> offchainreporting3_1.CertifiedPrepareOrCommit - 26, // 31: offchainreporting3_1.EpochStartProof.highest_certified_proof:type_name -> offchainreporting3_1.AttributedSignedHighestCertifiedTimestamp - 22, // 32: offchainreporting3_1.CertifiedPrepareOrCommit.prepare:type_name -> offchainreporting3_1.CertifiedPrepare - 23, // 33: offchainreporting3_1.CertifiedPrepareOrCommit.commit:type_name -> offchainreporting3_1.CertifiedCommit - 35, // 34: offchainreporting3_1.CertifiedPrepare.state_transition_outputs:type_name -> offchainreporting3_1.StateTransitionOutputs - 31, // 35: offchainreporting3_1.CertifiedPrepare.prepare_quorum_certificate:type_name -> offchainreporting3_1.AttributedPrepareSignature - 35, // 36: offchainreporting3_1.CertifiedCommit.state_transition_outputs:type_name -> offchainreporting3_1.StateTransitionOutputs - 32, // 37: offchainreporting3_1.CertifiedCommit.commit_quorum_certificate:type_name -> offchainreporting3_1.AttributedCommitSignature - 32, // 38: offchainreporting3_1.CertifiedCommittedReports.commit_quorum_certificate:type_name -> offchainreporting3_1.AttributedCommitSignature - 27, // 39: offchainreporting3_1.AttributedSignedHighestCertifiedTimestamp.signed_highest_certified_timestamp:type_name -> offchainreporting3_1.SignedHighestCertifiedTimestamp - 25, // 40: offchainreporting3_1.SignedHighestCertifiedTimestamp.highest_certified_timestamp:type_name -> offchainreporting3_1.HighestCertifiedTimestamp - 30, // 41: offchainreporting3_1.AttributedSignedObservation.signed_observation:type_name -> offchainreporting3_1.SignedObservation - 34, // 42: offchainreporting3_1.AttestedStateTransitionBlock.state_transition_block:type_name -> offchainreporting3_1.StateTransitionBlock - 32, // 43: offchainreporting3_1.AttestedStateTransitionBlock.attributed_signatures:type_name -> offchainreporting3_1.AttributedCommitSignature - 35, // 44: offchainreporting3_1.StateTransitionBlock.state_transition_outputs:type_name -> offchainreporting3_1.StateTransitionOutputs - 36, // 45: offchainreporting3_1.StateTransitionOutputs.write_set:type_name -> offchainreporting3_1.KeyValueModification - 28, // 46: offchainreporting3_1.StateTransitionInputs.attributed_observations:type_name -> offchainreporting3_1.AttributedObservation - 47, // [47:47] is the sub-list for method output_type - 47, // [47:47] is the sub-list for method input_type - 47, // [47:47] is the sub-list for extension type_name - 47, // [47:47] is the sub-list for extension extendee - 0, // [0:47] is the sub-list for field type_name + 29, // 23: offchainreporting3_1.MessageObservation.signed_observation:type_name -> offchainreporting3_1.SignedObservation + 28, // 24: offchainreporting3_1.MessageProposal.attributed_signed_observations:type_name -> offchainreporting3_1.AttributedSignedObservation + 32, // 25: offchainreporting3_1.MessageBlockSyncResponse.attested_state_transition_blocks:type_name -> offchainreporting3_1.AttestedStateTransitionBlock + 17, // 26: offchainreporting3_1.BoundingLeaf.leaf:type_name -> offchainreporting3_1.LeafKeyAndValueDigests + 16, // 27: offchainreporting3_1.MessageTreeSyncChunkResponse.key_values:type_name -> offchainreporting3_1.KeyValuePair + 18, // 28: offchainreporting3_1.MessageTreeSyncChunkResponse.bounding_leaves:type_name -> offchainreporting3_1.BoundingLeaf + 21, // 29: offchainreporting3_1.EpochStartProof.highest_certified:type_name -> offchainreporting3_1.CertifiedPrepareOrCommit + 25, // 30: offchainreporting3_1.EpochStartProof.highest_certified_proof:type_name -> offchainreporting3_1.AttributedSignedHighestCertifiedTimestamp + 22, // 31: offchainreporting3_1.CertifiedPrepareOrCommit.prepare:type_name -> offchainreporting3_1.CertifiedPrepare + 23, // 32: offchainreporting3_1.CertifiedPrepareOrCommit.commit:type_name -> offchainreporting3_1.CertifiedCommit + 30, // 33: offchainreporting3_1.CertifiedPrepare.prepare_quorum_certificate:type_name -> offchainreporting3_1.AttributedPrepareSignature + 31, // 34: offchainreporting3_1.CertifiedCommit.commit_quorum_certificate:type_name -> offchainreporting3_1.AttributedCommitSignature + 26, // 35: offchainreporting3_1.AttributedSignedHighestCertifiedTimestamp.signed_highest_certified_timestamp:type_name -> offchainreporting3_1.SignedHighestCertifiedTimestamp + 24, // 36: offchainreporting3_1.SignedHighestCertifiedTimestamp.highest_certified_timestamp:type_name -> offchainreporting3_1.HighestCertifiedTimestamp + 29, // 37: offchainreporting3_1.AttributedSignedObservation.signed_observation:type_name -> offchainreporting3_1.SignedObservation + 33, // 38: offchainreporting3_1.AttestedStateTransitionBlock.state_transition_block:type_name -> offchainreporting3_1.StateTransitionBlock + 31, // 39: offchainreporting3_1.AttestedStateTransitionBlock.attributed_signatures:type_name -> offchainreporting3_1.AttributedCommitSignature + 34, // 40: offchainreporting3_1.StateTransitionBlock.state_transition_outputs:type_name -> offchainreporting3_1.StateTransitionOutputs + 35, // 41: offchainreporting3_1.StateTransitionOutputs.write_set:type_name -> offchainreporting3_1.KeyValueModification + 27, // 42: offchainreporting3_1.StateTransitionInputs.attributed_observations:type_name -> offchainreporting3_1.AttributedObservation + 43, // [43:43] is the sub-list for method output_type + 43, // [43:43] is the sub-list for method input_type + 43, // [43:43] is the sub-list for extension type_name + 43, // [43:43] is the sub-list for extension extendee + 0, // [0:43] is the sub-list for field type_name } func init() { file_offchainreporting3_1_messages_proto_init() } @@ -3738,7 +3649,7 @@ func file_offchainreporting3_1_messages_proto_init() { } } file_offchainreporting3_1_messages_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MessageCertifiedCommitRequest); i { + switch v := v.(*MessageReportsPlusPrecursorRequest); i { case 0: return &v.state case 1: @@ -3750,7 +3661,7 @@ func file_offchainreporting3_1_messages_proto_init() { } } file_offchainreporting3_1_messages_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MessageCertifiedCommit); i { + switch v := v.(*MessageReportsPlusPrecursor); i { case 0: return &v.state case 1: @@ -3906,18 +3817,6 @@ func file_offchainreporting3_1_messages_proto_init() { } } file_offchainreporting3_1_messages_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CertifiedCommittedReports); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_offchainreporting3_1_messages_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*HighestCertifiedTimestamp); i { case 0: return &v.state @@ -3929,7 +3828,7 @@ func file_offchainreporting3_1_messages_proto_init() { return nil } } - file_offchainreporting3_1_messages_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { + file_offchainreporting3_1_messages_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*AttributedSignedHighestCertifiedTimestamp); i { case 0: return &v.state @@ -3941,7 +3840,7 @@ func file_offchainreporting3_1_messages_proto_init() { return nil } } - file_offchainreporting3_1_messages_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { + file_offchainreporting3_1_messages_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*SignedHighestCertifiedTimestamp); i { case 0: return &v.state @@ -3953,7 +3852,7 @@ func file_offchainreporting3_1_messages_proto_init() { return nil } } - file_offchainreporting3_1_messages_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { + file_offchainreporting3_1_messages_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*AttributedObservation); i { case 0: return &v.state @@ -3965,7 +3864,7 @@ func file_offchainreporting3_1_messages_proto_init() { return nil } } - file_offchainreporting3_1_messages_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { + file_offchainreporting3_1_messages_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*AttributedSignedObservation); i { case 0: return &v.state @@ -3977,7 +3876,7 @@ func file_offchainreporting3_1_messages_proto_init() { return nil } } - file_offchainreporting3_1_messages_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { + file_offchainreporting3_1_messages_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*SignedObservation); i { case 0: return &v.state @@ -3989,7 +3888,7 @@ func file_offchainreporting3_1_messages_proto_init() { return nil } } - file_offchainreporting3_1_messages_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { + file_offchainreporting3_1_messages_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*AttributedPrepareSignature); i { case 0: return &v.state @@ -4001,7 +3900,7 @@ func file_offchainreporting3_1_messages_proto_init() { return nil } } - file_offchainreporting3_1_messages_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { + file_offchainreporting3_1_messages_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*AttributedCommitSignature); i { case 0: return &v.state @@ -4013,7 +3912,7 @@ func file_offchainreporting3_1_messages_proto_init() { return nil } } - file_offchainreporting3_1_messages_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { + file_offchainreporting3_1_messages_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*AttestedStateTransitionBlock); i { case 0: return &v.state @@ -4025,7 +3924,7 @@ func file_offchainreporting3_1_messages_proto_init() { return nil } } - file_offchainreporting3_1_messages_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} { + file_offchainreporting3_1_messages_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*StateTransitionBlock); i { case 0: return &v.state @@ -4037,7 +3936,7 @@ func file_offchainreporting3_1_messages_proto_init() { return nil } } - file_offchainreporting3_1_messages_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} { + file_offchainreporting3_1_messages_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*StateTransitionOutputs); i { case 0: return &v.state @@ -4049,7 +3948,7 @@ func file_offchainreporting3_1_messages_proto_init() { return nil } } - file_offchainreporting3_1_messages_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} { + file_offchainreporting3_1_messages_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*KeyValueModification); i { case 0: return &v.state @@ -4061,7 +3960,7 @@ func file_offchainreporting3_1_messages_proto_init() { return nil } } - file_offchainreporting3_1_messages_proto_msgTypes[37].Exporter = func(v interface{}, i int) interface{} { + file_offchainreporting3_1_messages_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*StateTransitionInputs); i { case 0: return &v.state @@ -4073,7 +3972,7 @@ func file_offchainreporting3_1_messages_proto_init() { return nil } } - file_offchainreporting3_1_messages_proto_msgTypes[38].Exporter = func(v interface{}, i int) interface{} { + file_offchainreporting3_1_messages_proto_msgTypes[37].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*MessageBlobOffer); i { case 0: return &v.state @@ -4085,7 +3984,7 @@ func file_offchainreporting3_1_messages_proto_init() { return nil } } - file_offchainreporting3_1_messages_proto_msgTypes[39].Exporter = func(v interface{}, i int) interface{} { + file_offchainreporting3_1_messages_proto_msgTypes[38].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*MessageBlobChunkRequest); i { case 0: return &v.state @@ -4097,7 +3996,7 @@ func file_offchainreporting3_1_messages_proto_init() { return nil } } - file_offchainreporting3_1_messages_proto_msgTypes[40].Exporter = func(v interface{}, i int) interface{} { + file_offchainreporting3_1_messages_proto_msgTypes[39].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*MessageBlobChunkResponse); i { case 0: return &v.state @@ -4109,7 +4008,7 @@ func file_offchainreporting3_1_messages_proto_init() { return nil } } - file_offchainreporting3_1_messages_proto_msgTypes[41].Exporter = func(v interface{}, i int) interface{} { + file_offchainreporting3_1_messages_proto_msgTypes[40].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*MessageBlobOfferResponse); i { case 0: return &v.state @@ -4132,8 +4031,8 @@ func file_offchainreporting3_1_messages_proto_init() { (*MessageWrapper_MessagePrepare)(nil), (*MessageWrapper_MessageCommit)(nil), (*MessageWrapper_MessageReportSignatures)(nil), - (*MessageWrapper_MessageCertifiedCommitRequest)(nil), - (*MessageWrapper_MessageCertifiedCommit)(nil), + (*MessageWrapper_MessageReportsPlusPrecursorRequest)(nil), + (*MessageWrapper_MessageReportsPlusPrecursor)(nil), (*MessageWrapper_MessageBlockSyncRequest)(nil), (*MessageWrapper_MessageBlockSyncResponse)(nil), (*MessageWrapper_MessageStateSyncSummary)(nil), @@ -4154,7 +4053,7 @@ func file_offchainreporting3_1_messages_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_offchainreporting3_1_messages_proto_rawDesc, NumEnums: 0, - NumMessages: 42, + NumMessages: 41, NumExtensions: 0, NumServices: 0, }, diff --git a/offchainreporting2plus/internal/ocr3_1/serialization/serialization.go b/offchainreporting2plus/internal/ocr3_1/serialization/serialization.go index ce53ef82..fe2bf39f 100644 --- a/offchainreporting2plus/internal/ocr3_1/serialization/serialization.go +++ b/offchainreporting2plus/internal/ocr3_1/serialization/serialization.go @@ -5,6 +5,7 @@ import ( "github.com/smartcontractkit/libocr/commontypes" "github.com/smartcontractkit/libocr/internal/jmt" + "github.com/smartcontractkit/libocr/internal/mt" "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/ocr3_1/protocol" "github.com/smartcontractkit/libocr/offchainreporting2plus/types" @@ -67,6 +68,7 @@ func SerializePacemakerState(m protocol.PacemakerState) ([]byte, error) { } func SerializeBlobMeta(m protocol.BlobMeta) ([]byte, error) { + tpm := toProtoMessage[struct{}]{} pb := BlobMeta{ // zero-initialize protobuf built-ins protoimpl.MessageState{}, @@ -74,8 +76,23 @@ func SerializeBlobMeta(m protocol.BlobMeta) ([]byte, error) { nil, // fields m.PayloadLength, - m.ChunksHave, + m.ChunkHaves, + tpm.chunkDigests(m.ChunkDigests), m.ExpirySeqNr, + uint32(m.Submitter), + } + return proto.Marshal(&pb) +} + +func SerializeBlobQuotaStats(bqs protocol.BlobQuotaStats) ([]byte, error) { + pb := BlobQuotaStats{ + // zero-initialize protobuf built-ins + protoimpl.MessageState{}, + 0, + nil, + // fields + bqs.Count, + bqs.CumulativePayloadLength, } return proto.Marshal(&pb) } @@ -86,6 +103,12 @@ func SerializeAttestedStateTransitionBlock(astb protocol.AttestedStateTransition return proto.Marshal(tpm.attestedStateTransitionBlock(astb)) } +func SerializeStateTransitionBlock(stb protocol.StateTransitionBlock) ([]byte, error) { + tpm := toProtoMessage[struct{}]{} + + return proto.Marshal(tpm.stateTransitionBlock(stb)) +} + // Deserialize decodes a binary payload into a protocol.Message func Deserialize[RI any](n int, b []byte, requestHandle types.RequestHandle) (protocol.Message[RI], *MessageWrapper, error) { pb := &MessageWrapper{} @@ -156,10 +179,28 @@ func DeserializeBlobMeta(b []byte) (protocol.BlobMeta, error) { if err := proto.Unmarshal(b, &pb); err != nil { return protocol.BlobMeta{}, err } + fpm := fromProtoMessage[struct{}]{} + chunkDigests, err := fpm.chunkDigests(pb.ChunkDigests) + if err != nil { + return protocol.BlobMeta{}, err + } return protocol.BlobMeta{ pb.PayloadLength, pb.ChunkHaves, + chunkDigests, pb.ExpirySeqNr, + commontypes.OracleID(pb.Submitter), + }, nil +} + +func DeserializeBlobQuotaStats(b []byte) (protocol.BlobQuotaStats, error) { + pb := BlobQuotaStats{} + if err := proto.Unmarshal(b, &pb); err != nil { + return protocol.BlobQuotaStats{}, err + } + return protocol.BlobQuotaStats{ + pb.Count, + pb.CumulativePayloadLength, }, nil } @@ -176,6 +217,16 @@ func DeserializeAttestedStateTransitionBlock(b []byte) (protocol.AttestedStateTr return fpm.attestedStateTransitionBlock(&pb) } +func DeserializeStateTransitionBlock(b []byte) (protocol.StateTransitionBlock, error) { + pb := StateTransitionBlock{} + if err := proto.Unmarshal(b, &pb); err != nil { + return protocol.StateTransitionBlock{}, err + } + + fpm := fromProtoMessage[struct{}]{} + return fpm.stateTransitionBlock(&pb) +} + // // *toProtoMessage // @@ -216,6 +267,7 @@ func (tpm *toProtoMessage[RI]) messageWrapper(m protocol.Message[RI]) (*MessageW // fields uint64(v.Epoch), tpm.epochStartProof(v.EpochStartProof), + v.Abdicate, } msgWrapper.Msg = &MessageWrapper_MessageEpochStart{pm} case protocol.MessageRoundStart[RI]: @@ -292,10 +344,11 @@ func (tpm *toProtoMessage[RI]) messageWrapper(m protocol.Message[RI]) (*MessageW // fields v.SeqNr, v.ReportSignatures, + v.ReportsPlusPrecursorDigest[:], } msgWrapper.Msg = &MessageWrapper_MessageReportSignatures{pm} - case protocol.MessageCertifiedCommitRequest[RI]: - pm := &MessageCertifiedCommitRequest{ + case protocol.MessageReportsPlusPrecursorRequest[RI]: + pm := &MessageReportsPlusPrecursorRequest{ // zero-initialize protobuf built-ins protoimpl.MessageState{}, 0, @@ -303,17 +356,18 @@ func (tpm *toProtoMessage[RI]) messageWrapper(m protocol.Message[RI]) (*MessageW // fields v.SeqNr, } - msgWrapper.Msg = &MessageWrapper_MessageCertifiedCommitRequest{pm} - case protocol.MessageCertifiedCommit[RI]: - pm := &MessageCertifiedCommit{ + msgWrapper.Msg = &MessageWrapper_MessageReportsPlusPrecursorRequest{pm} + case protocol.MessageReportsPlusPrecursor[RI]: + pm := &MessageReportsPlusPrecursor{ // zero-initialize protobuf built-ins protoimpl.MessageState{}, 0, nil, // fields - tpm.CertifiedCommittedReports(v.CertifiedCommittedReports), + v.SeqNr, + v.ReportsPlusPrecursor, } - msgWrapper.Msg = &MessageWrapper_MessageCertifiedCommit{pm} + msgWrapper.Msg = &MessageWrapper_MessageReportsPlusPrecursor{pm} case protocol.MessageBlockSyncRequest[RI]: pm := &MessageBlockSyncRequest{ // zero-initialize protobuf built-ins @@ -387,7 +441,7 @@ func (tpm *toProtoMessage[RI]) messageWrapper(m protocol.Message[RI]) (*MessageW 0, nil, // fields - tpm.chunkDigests(v.ChunkDigests), + v.ChunkDigestsRoot[:], v.PayloadLength, v.ExpirySeqNr, } @@ -416,6 +470,10 @@ func (tpm *toProtoMessage[RI]) messageWrapper(m protocol.Message[RI]) (*MessageW } msgWrapper.Msg = &MessageWrapper_MessageBlobChunkRequest{pm} case protocol.MessageBlobChunkResponse[RI]: + pbProof := make([][]byte, len(v.Proof)) + for i, p := range v.Proof { + pbProof[i] = p[:] + } pm := &MessageBlobChunkResponse{ // zero-initialize protobuf built-ins protoimpl.MessageState{}, @@ -426,6 +484,7 @@ func (tpm *toProtoMessage[RI]) messageWrapper(m protocol.Message[RI]) (*MessageW v.ChunkIndex, v.GoAway, v.Chunk, + pbProof, } msgWrapper.Msg = &MessageWrapper_MessageBlobChunkResponse{pm} default: @@ -473,9 +532,9 @@ func (tpm *toProtoMessage[RI]) certifiedPrepareOrCommit(cpoc protocol.CertifiedP v.Epoch(), v.SeqNr(), v.StateTransitionInputsDigest[:], - tpm.stateTransitionOutputs(v.StateTransitionOutputs), + v.StateTransitionOutputsDigest[:], v.StateRootDigest[:], - v.ReportsPlusPrecursor[:], + v.ReportsPlusPrecursorDigest[:], prepareQuorumCertificate, }}, } @@ -517,38 +576,9 @@ func (tpm *toProtoMessage[RI]) CertifiedCommit(cpocc protocol.CertifiedCommit) * cpocc.Epoch(), cpocc.SeqNr(), cpocc.StateTransitionInputsDigest[:], - tpm.stateTransitionOutputs(cpocc.StateTransitionOutputs), + cpocc.StateTransitionOutputsDigest[:], cpocc.StateRootDigest[:], - cpocc.ReportsPlusPrecursor[:], - commitQuorumCertificate, - } -} - -func (tpm *toProtoMessage[RI]) CertifiedCommittedReports(ccr protocol.CertifiedCommittedReports[RI]) *CertifiedCommittedReports { - commitQuorumCertificate := make([]*AttributedCommitSignature, 0, len(ccr.CommitQuorumCertificate)) - for _, aps := range ccr.CommitQuorumCertificate { - commitQuorumCertificate = append(commitQuorumCertificate, &AttributedCommitSignature{ - // zero-initialize protobuf built-ins - protoimpl.MessageState{}, - 0, - nil, - // fields - aps.Signature, - uint32(aps.Signer), - }) - } - return &CertifiedCommittedReports{ - // zero-initialize protobuf built-ins - protoimpl.MessageState{}, - 0, - nil, - // fields - uint64(ccr.CommitEpoch), - ccr.SeqNr, - ccr.StateTransitionInputsDigest[:], - ccr.StateTransitionOutputDigest[:], - ccr.StateRootDigest[:], - ccr.ReportsPlusPrecursor[:], + cpocc.ReportsPlusPrecursorDigest[:], commitQuorumCertificate, } } @@ -666,7 +696,7 @@ func (tpm *toProtoMessage[RI]) stateTransitionBlock(stb protocol.StateTransition stb.StateTransitionInputsDigest[:], tpm.stateTransitionOutputs(stb.StateTransitionOutputs), stb.StateRootDigest[:], - stb.ReportsPlusPrecursor, + stb.ReportsPlusPrecursorDigest[:], } } @@ -792,10 +822,10 @@ func (fpm *fromProtoMessage[RI]) messageWrapper(wrapper *MessageWrapper) (protoc return fpm.messageCommit(wrapper.GetMessageCommit()) case *MessageWrapper_MessageReportSignatures: return fpm.messageReportSignatures(wrapper.GetMessageReportSignatures()) - case *MessageWrapper_MessageCertifiedCommitRequest: - return fpm.messageCertifiedCommitRequest(wrapper.GetMessageCertifiedCommitRequest()) - case *MessageWrapper_MessageCertifiedCommit: - return fpm.MessageCertifiedCommit(wrapper.GetMessageCertifiedCommit()) + case *MessageWrapper_MessageReportsPlusPrecursorRequest: + return fpm.messageReportsPlusPrecursorRequest(wrapper.GetMessageReportsPlusPrecursorRequest()) + case *MessageWrapper_MessageReportsPlusPrecursor: + return fpm.messageReportsPlusPrecursor(wrapper.GetMessageReportsPlusPrecursor()) case *MessageWrapper_MessageBlockSyncRequest: return fpm.messageBlockSyncRequest(wrapper.GetMessageBlockSyncRequest()) case *MessageWrapper_MessageBlockSyncResponse: @@ -859,6 +889,7 @@ func (fpm *fromProtoMessage[RI]) messageEpochStart(m *MessageEpochStart) (protoc return protocol.MessageEpochStart[RI]{ m.Epoch, srqc, + m.Abdicate, }, nil } @@ -925,14 +956,14 @@ func (fpm *fromProtoMessage[RI]) certifiedPrepare(m *CertifiedPrepare) (protocol if m == nil { return protocol.CertifiedPrepare{}, fmt.Errorf("unable to extract a CertifiedPrepare value") } - outputs, err := fpm.stateTransitionOutputs(m.StateTransitionOutputs) - if err != nil { - return protocol.CertifiedPrepare{}, err - } var inputsDigest protocol.StateTransitionInputsDigest copy(inputsDigest[:], m.StateTransitionInputsDigest) + var outputsDigest protocol.StateTransitionOutputDigest + copy(outputsDigest[:], m.StateTransitionOutputsDigest) var stateRootDigest protocol.StateRootDigest copy(stateRootDigest[:], m.StateRootDigest) + var reportsPlusPrecursorDigest protocol.ReportsPlusPrecursorDigest + copy(reportsPlusPrecursorDigest[:], m.ReportsPlusPrecursorDigest) prepareQuorumCertificate := make([]protocol.AttributedPrepareSignature, 0, len(m.PrepareQuorumCertificate)) for _, aps := range m.PrepareQuorumCertificate { @@ -949,9 +980,9 @@ func (fpm *fromProtoMessage[RI]) certifiedPrepare(m *CertifiedPrepare) (protocol m.Epoch, m.SeqNr, inputsDigest, - outputs, + outputsDigest, stateRootDigest, - m.ReportsPlusPrecursor, + reportsPlusPrecursorDigest, prepareQuorumCertificate, }, nil @@ -961,14 +992,14 @@ func (fpm *fromProtoMessage[RI]) certifiedCommit(m *CertifiedCommit) (protocol.C if m == nil { return protocol.CertifiedCommit{}, fmt.Errorf("unable to extract a CertifiedCommit value") } - outputs, err := fpm.stateTransitionOutputs(m.StateTransitionOutputs) - if err != nil { - return protocol.CertifiedCommit{}, err - } var inputsDigest protocol.StateTransitionInputsDigest copy(inputsDigest[:], m.StateTransitionInputsDigest) + var outputsDigest protocol.StateTransitionOutputDigest + copy(outputsDigest[:], m.StateTransitionOutputsDigest) var stateRootDigest protocol.StateRootDigest copy(stateRootDigest[:], m.StateRootDigest) + var reportsPlusPrecursorDigest protocol.ReportsPlusPrecursorDigest + copy(reportsPlusPrecursorDigest[:], m.ReportsPlusPrecursorDigest) commitQuorumCertificate := make([]protocol.AttributedCommitSignature, 0, len(m.CommitQuorumCertificate)) for _, aps := range m.CommitQuorumCertificate { @@ -985,42 +1016,9 @@ func (fpm *fromProtoMessage[RI]) certifiedCommit(m *CertifiedCommit) (protocol.C m.Epoch, m.SeqNr, inputsDigest, - outputs, - stateRootDigest, - m.ReportsPlusPrecursor, - commitQuorumCertificate, - }, nil -} - -func (fpm *fromProtoMessage[RI]) certifiedCommittedReports(m *CertifiedCommittedReports) (protocol.CertifiedCommittedReports[RI], error) { - if m == nil { - return protocol.CertifiedCommittedReports[RI]{}, fmt.Errorf("unable to extract a CertifiedCommittedReports value") - } - var inputsDigest protocol.StateTransitionInputsDigest - copy(inputsDigest[:], m.StateTransitionInputsDigest) - var outputsDigest protocol.StateTransitionOutputDigest - copy(outputsDigest[:], m.StateTransitionOutputDigest) - var stateRootDigest protocol.StateRootDigest - copy(stateRootDigest[:], m.StateRootDigest) - - commitQuorumCertificate := make([]protocol.AttributedCommitSignature, 0, len(m.CommitQuorumCertificate)) - for _, aps := range m.CommitQuorumCertificate { - signer, err := fpm.oracleID(aps.GetSigner()) - if err != nil { - return protocol.CertifiedCommittedReports[RI]{}, err - } - commitQuorumCertificate = append(commitQuorumCertificate, protocol.AttributedCommitSignature{ - aps.GetSignature(), - signer, - }) - } - return protocol.CertifiedCommittedReports[RI]{ - m.CommitEpoch, - m.SeqNr, - inputsDigest, outputsDigest, stateRootDigest, - m.ReportsPlusPrecursor, + reportsPlusPrecursorDigest, commitQuorumCertificate, }, nil } @@ -1113,31 +1111,33 @@ func (fpm *fromProtoMessage[RI]) messageReportSignatures(m *MessageReportSignatu if m == nil { return protocol.MessageReportSignatures[RI]{}, fmt.Errorf("unable to extract a MessageReportSignatures value") } + + var reportsPlusPrecursorDigest protocol.ReportsPlusPrecursorDigest + copy(reportsPlusPrecursorDigest[:], m.ReportsPlusPrecursorDigest) + return protocol.MessageReportSignatures[RI]{ m.SeqNr, m.ReportSignatures, + reportsPlusPrecursorDigest, }, nil } -func (fpm *fromProtoMessage[RI]) messageCertifiedCommitRequest(m *MessageCertifiedCommitRequest) (protocol.MessageCertifiedCommitRequest[RI], error) { +func (fpm *fromProtoMessage[RI]) messageReportsPlusPrecursorRequest(m *MessageReportsPlusPrecursorRequest) (protocol.MessageReportsPlusPrecursorRequest[RI], error) { if m == nil { - return protocol.MessageCertifiedCommitRequest[RI]{}, fmt.Errorf("unable to extract a MessageCertifiedCommitRequest value") + return protocol.MessageReportsPlusPrecursorRequest[RI]{}, fmt.Errorf("unable to extract a MessageReportsPlusPrecursorRequest value") } - return protocol.MessageCertifiedCommitRequest[RI]{ + return protocol.MessageReportsPlusPrecursorRequest[RI]{ m.SeqNr, }, nil } -func (fpm *fromProtoMessage[RI]) MessageCertifiedCommit(m *MessageCertifiedCommit) (protocol.MessageCertifiedCommit[RI], error) { +func (fpm *fromProtoMessage[RI]) messageReportsPlusPrecursor(m *MessageReportsPlusPrecursor) (protocol.MessageReportsPlusPrecursor[RI], error) { if m == nil { - return protocol.MessageCertifiedCommit[RI]{}, fmt.Errorf("unable to extract a MessageCertifiedCommit value") + return protocol.MessageReportsPlusPrecursor[RI]{}, fmt.Errorf("unable to extract a MessageReportsPlusPrecursor value") } - cpocc, err := fpm.certifiedCommittedReports(m.CertifiedCommittedReports) - if err != nil { - return protocol.MessageCertifiedCommit[RI]{}, err - } - return protocol.MessageCertifiedCommit[RI]{ - cpocc, + return protocol.MessageReportsPlusPrecursor[RI]{ + m.SeqNr, + m.ReportsPlusPrecursor, }, nil } @@ -1199,6 +1199,7 @@ func (fpm *fromProtoMessage[RI]) messageBlockSyncRequest(m *MessageBlockSyncRequ } return protocol.MessageBlockSyncRequest[RI]{ fpm.requestHandle, + types.EmptyRequestInfoForInboundRequest, m.StartSeqNr, m.EndExclSeqNr, }, nil @@ -1213,7 +1214,7 @@ func (fpm *fromProtoMessage[RI]) messageBlockSyncResponse(m *MessageBlockSyncRes return protocol.MessageBlockSyncResponse[RI]{}, err } return protocol.MessageBlockSyncResponse[RI]{ - nil, // TODO: consider using a sentinel value here, e.g. "EmptyRequestHandleForInboundResponse" + types.EmptyRequestHandleForInboundResponse, m.RequestStartSeqNr, m.RequestEndExclSeqNr, astbs, @@ -1267,18 +1268,19 @@ func (fpm *fromProtoMessage[RI]) stateTransitionBlock(m *StateTransitionBlock) ( copy(inputsDigest[:], m.StateTransitionInputsDigest) var stateRootDigest protocol.StateRootDigest copy(stateRootDigest[:], m.StateRootDigest) - outputs, err := fpm.stateTransitionOutputs(m.StateTransitionOutputs) if err != nil { return protocol.StateTransitionBlock{}, err } + var reportsPlusPrecursorDigest protocol.ReportsPlusPrecursorDigest + copy(reportsPlusPrecursorDigest[:], m.ReportsPlusPrecursorDigest) return protocol.StateTransitionBlock{ m.Epoch, m.SeqNr, inputsDigest, outputs, stateRootDigest, - m.ReportsPlusPrecursor, + reportsPlusPrecursorDigest, }, nil } @@ -1329,14 +1331,12 @@ func (fpm *fromProtoMessage[RI]) messageBlobOffer(m *MessageBlobOffer) (protocol if m == nil { return protocol.MessageBlobOffer[RI]{}, fmt.Errorf("unable to extract a MessageBlobOffer value") } - chunkDigests, err := fpm.chunkDigests(m.ChunkDigests) - if err != nil { - return protocol.MessageBlobOffer[RI]{}, err - } + var chunkDigestsRoot mt.Digest + copy(chunkDigestsRoot[:], m.ChunkDigestsRoot) return protocol.MessageBlobOffer[RI]{ fpm.requestHandle, - nil, - chunkDigests, + types.EmptyRequestInfoForInboundRequest, + chunkDigestsRoot, m.PayloadLength, m.ExpirySeqNr, }, nil @@ -1362,7 +1362,7 @@ func (fpm *fromProtoMessage[RI]) messageBlobOfferResponse(m *MessageBlobOfferRes copy(blobDigest[:], m.BlobDigest) return protocol.MessageBlobOfferResponse[RI]{ - nil, // TODO: consider using a sentinel value here, e.g. "EmptyRequestHandleForInboundResponse" + types.EmptyRequestHandleForInboundResponse, blobDigest, m.RejectOffer, m.Signature, @@ -1379,7 +1379,7 @@ func (fpm *fromProtoMessage[RI]) messageBlobChunkRequest(m *MessageBlobChunkRequ return protocol.MessageBlobChunkRequest[RI]{ fpm.requestHandle, - nil, + types.EmptyRequestInfoForInboundRequest, blobDigest, m.ChunkIndex, }, nil @@ -1393,12 +1393,20 @@ func (fpm *fromProtoMessage[RI]) messageBlobChunkResponse(m *MessageBlobChunkRes var blobDigest protocol.BlobDigest copy(blobDigest[:], m.BlobDigest) + proof := make([]mt.Digest, 0, len(m.Proof)) + for _, p := range m.Proof { + var pmt mt.Digest + copy(pmt[:], p) + proof = append(proof, pmt) + } + return protocol.MessageBlobChunkResponse[RI]{ - nil, // TODO: consider using a sentinel value here, e.g. "EmptyRequestHandleForInboundResponse" + types.EmptyRequestHandleForInboundResponse, blobDigest, m.ChunkIndex, m.GoAway, m.Chunk, + proof, }, nil } @@ -1416,6 +1424,7 @@ func (fpm *fromProtoMessage[RI]) messageTreeSyncChunkRequest(m *MessageTreeSyncC } return protocol.MessageTreeSyncChunkRequest[RI]{ fpm.requestHandle, + types.EmptyRequestInfoForInboundRequest, m.ToSeqNr, startIndex, endInclIndex, @@ -1514,7 +1523,7 @@ func (fpm *fromProtoMessage[RI]) messageTreeSyncChunkResponse(m *MessageTreeSync return protocol.MessageTreeSyncChunkResponse[RI]{}, err } return protocol.MessageTreeSyncChunkResponse[RI]{ - nil, // TODO: consider using a sentinel value here, e.g. "EmptyRequestHandleForInboundResponse" + types.EmptyRequestHandleForInboundResponse, m.ToSeqNr, startIndex, requestEndInclIndex, diff --git a/offchainreporting2plus/internal/shim/ocr3_1_key_value_store.go b/offchainreporting2plus/internal/shim/ocr3_1_key_value_store.go index 687666fb..bdc9086e 100644 --- a/offchainreporting2plus/internal/shim/ocr3_1_key_value_store.go +++ b/offchainreporting2plus/internal/shim/ocr3_1_key_value_store.go @@ -15,6 +15,7 @@ import ( "github.com/smartcontractkit/libocr/internal/jmt" "github.com/smartcontractkit/libocr/internal/singlewriter" "github.com/smartcontractkit/libocr/internal/util" + "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config" "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/ocr3_1/blobtypes" "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/ocr3_1/protocol" "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/ocr3_1/serialization" @@ -25,6 +26,7 @@ type SemanticOCR3_1KeyValueDatabase struct { conflictTracker *singlewriter.ConflictTracker KeyValueDatabase ocr3_1types.KeyValueDatabase Limits ocr3_1types.ReportingPluginLimits + config ocr3_1config.PublicConfig logger commontypes.Logger metrics *keyValueMetrics } @@ -34,6 +36,7 @@ var _ protocol.KeyValueDatabase = &SemanticOCR3_1KeyValueDatabase{} func NewSemanticOCR3_1KeyValueDatabase( keyValueDatabase ocr3_1types.KeyValueDatabase, limits ocr3_1types.ReportingPluginLimits, + config ocr3_1config.PublicConfig, logger commontypes.Logger, metricsRegisterer prometheus.Registerer, ) *SemanticOCR3_1KeyValueDatabase { @@ -41,11 +44,27 @@ func NewSemanticOCR3_1KeyValueDatabase( singlewriter.NewConflictTracker(), keyValueDatabase, limits, + config, logger, newKeyValueMetrics(metricsRegisterer, logger), } } +func (s *SemanticOCR3_1KeyValueDatabase) newReadWriteTransaction(tx ocr3_1types.KeyValueDatabaseReadWriteTransaction, nilOrSeqNr *uint64) *SemanticOCR3_1KeyValueDatabaseReadWriteTransaction { + return &SemanticOCR3_1KeyValueDatabaseReadWriteTransaction{ + SemanticOCR3_1KeyValueDatabaseReadTransaction{ + tx, + s.config, + }, + tx, + s.metrics, + sync.Mutex{}, + newLimitCheckWriteSet(s.Limits), + nilOrSeqNr, + false, + } +} + func (s *SemanticOCR3_1KeyValueDatabase) Close() error { err := s.KeyValueDatabase.Close() s.metrics.Close() @@ -62,19 +81,11 @@ func (s *SemanticOCR3_1KeyValueDatabase) HighestCommittedSeqNr() (uint64, error) } func (s *SemanticOCR3_1KeyValueDatabase) NewSerializedReadWriteTransaction(postSeqNr uint64) (protocol.KeyValueDatabaseReadWriteTransaction, error) { - fakeTx, err := singlewriter.NewSerializedTransaction(s.KeyValueDatabase, s.conflictTracker) + rawTx, err := singlewriter.NewSerializedTransaction(s.KeyValueDatabase, s.conflictTracker) if err != nil { return nil, fmt.Errorf("failed to create read write transaction: %w", err) } - tx := &SemanticOCR3_1KeyValueDatabaseReadWriteTransaction{ - &SemanticOCR3_1KeyValueDatabaseReadTransaction{fakeTx, s.Limits}, - fakeTx, - s.metrics, - sync.Mutex{}, - newLimitCheckWriteSet(s.Limits.MaxKeyValueModifiedKeysPlusValuesLength), - &postSeqNr, - false, - } + tx := s.newReadWriteTransaction(rawTx, &postSeqNr) highestCommittedSeqNr, err := tx.ReadHighestCommittedSeqNr() if err != nil { tx.Discard() @@ -100,36 +111,19 @@ func (s *SemanticOCR3_1KeyValueDatabase) NewSerializedReadWriteTransaction(postS } func (s *SemanticOCR3_1KeyValueDatabase) NewSerializedReadWriteTransactionUnchecked() (protocol.KeyValueDatabaseReadWriteTransaction, error) { - fakeTx, err := singlewriter.NewSerializedTransaction(s.KeyValueDatabase, s.conflictTracker) + rawTx, err := singlewriter.NewSerializedTransaction(s.KeyValueDatabase, s.conflictTracker) if err != nil { return nil, fmt.Errorf("failed to create read write transaction: %w", err) } - tx := &SemanticOCR3_1KeyValueDatabaseReadWriteTransaction{ - &SemanticOCR3_1KeyValueDatabaseReadTransaction{fakeTx, s.Limits}, - fakeTx, - s.metrics, - sync.Mutex{}, - newLimitCheckWriteSet(s.Limits.MaxKeyValueModifiedKeysPlusValuesLength), - nil, - false, - } - return tx, nil + return s.newReadWriteTransaction(rawTx, nil), nil } func (s *SemanticOCR3_1KeyValueDatabase) NewUnserializedReadWriteTransactionUnchecked() (protocol.KeyValueDatabaseReadWriteTransaction, error) { - fakeTx, err := singlewriter.NewUnserializedTransaction(s.KeyValueDatabase) + rawTx, err := singlewriter.NewUnserializedTransaction(s.KeyValueDatabase) if err != nil { return nil, fmt.Errorf("failed to create read write transaction: %w", err) } - return &SemanticOCR3_1KeyValueDatabaseReadWriteTransaction{ - &SemanticOCR3_1KeyValueDatabaseReadTransaction{fakeTx, s.Limits}, - fakeTx, - s.metrics, - sync.Mutex{}, - newLimitCheckWriteSet(s.Limits.MaxKeyValueModifiedKeysPlusValuesLength), - nil, - false, - }, nil + return s.newReadWriteTransaction(rawTx, nil), nil } func (s *SemanticOCR3_1KeyValueDatabase) NewReadTransaction(postSeqNr uint64) (protocol.KeyValueDatabaseReadTransaction, error) { @@ -169,17 +163,17 @@ func (s *SemanticOCR3_1KeyValueDatabase) NewReadTransactionUnchecked() (protocol if err != nil { return nil, fmt.Errorf("failed to create read transaction: %w", err) } - return &SemanticOCR3_1KeyValueDatabaseReadTransaction{tx, s.Limits}, nil + return &SemanticOCR3_1KeyValueDatabaseReadTransaction{tx, s.config}, nil } type SemanticOCR3_1KeyValueDatabaseReadWriteTransaction struct { - protocol.KeyValueDatabaseReadTransaction // inherit all read implementations - rawTransaction ocr3_1types.KeyValueDatabaseReadWriteTransaction - metrics *keyValueMetrics - mu sync.Mutex - nilOrWriteSet *limitCheckWriteSet - nilOrSeqNr *uint64 - closedForWriting bool + SemanticOCR3_1KeyValueDatabaseReadTransaction // inherit all read implementations + rawTransaction ocr3_1types.KeyValueDatabaseReadWriteTransaction + metrics *keyValueMetrics + mu sync.Mutex + nilOrWriteSet *limitCheckWriteSet + nilOrSeqNr *uint64 + closedForWriting bool } var _ protocol.KeyValueDatabaseReadWriteTransaction = &SemanticOCR3_1KeyValueDatabaseReadWriteTransaction{} @@ -213,8 +207,8 @@ func (s *SemanticOCR3_1KeyValueDatabaseReadWriteTransaction) Commit() error { } func (s *SemanticOCR3_1KeyValueDatabaseReadWriteTransaction) Delete(key []byte) error { - if !(len(key) <= ocr3_1types.MaxMaxKeyValueKeyLength) { - return fmt.Errorf("key length %d exceeds maximum %d", len(key), ocr3_1types.MaxMaxKeyValueKeyLength) + if !(len(key) <= ocr3_1types.MaxMaxKeyValueKeyBytes) { + return fmt.Errorf("key length %d exceeds maximum %d", len(key), ocr3_1types.MaxMaxKeyValueKeyBytes) } s.mu.Lock() @@ -380,15 +374,15 @@ func (s *SemanticOCR3_1KeyValueDatabaseReadWriteTransaction) CloseWriteSet() (pr s, s, s, - protocol.PrevRootVersion(*s.nilOrSeqNr), - protocol.RootVersion(*s.nilOrSeqNr), + protocol.PrevRootVersion(*s.nilOrSeqNr, s.config), + protocol.RootVersion(*s.nilOrSeqNr, s.config), keyValueUpdates, ) if err != nil { return protocol.StateRootDigest{}, fmt.Errorf("failed to batch update: %w", err) } - stateRootDigest, err := jmt.ReadRootDigest(s, s, protocol.RootVersion(*s.nilOrSeqNr)) + stateRootDigest, err := jmt.ReadRootDigest(s, s, protocol.RootVersion(*s.nilOrSeqNr, s.config)) if err != nil { return protocol.StateRootDigest{}, fmt.Errorf("failed to read root digest: %w", err) } @@ -425,11 +419,11 @@ func (s *SemanticOCR3_1KeyValueDatabaseReadWriteTransaction) Write(key []byte, v s.metrics.txWriteDurationNanoseconds.Observe(float64(time.Since(start).Nanoseconds())) }() - if !(len(key) <= ocr3_1types.MaxMaxKeyValueKeyLength) { - return fmt.Errorf("key length %d exceeds maximum %d", len(key), ocr3_1types.MaxMaxKeyValueKeyLength) + if !(len(key) <= ocr3_1types.MaxMaxKeyValueKeyBytes) { + return fmt.Errorf("key length %d exceeds maximum %d", len(key), ocr3_1types.MaxMaxKeyValueKeyBytes) } - if !(len(value) <= ocr3_1types.MaxMaxKeyValueValueLength) { - return fmt.Errorf("value length %d exceeds maximum %d", len(value), ocr3_1types.MaxMaxKeyValueValueLength) + if !(len(value) <= ocr3_1types.MaxMaxKeyValueValueBytes) { + return fmt.Errorf("value length %d exceeds maximum %d", len(value), ocr3_1types.MaxMaxKeyValueValueBytes) } value = util.NilCoalesceSlice(value) @@ -458,7 +452,7 @@ func (s *SemanticOCR3_1KeyValueDatabaseReadWriteTransaction) Write(key []byte, v type SemanticOCR3_1KeyValueDatabaseReadTransaction struct { rawTransaction ocr3_1types.KeyValueDatabaseReadTransaction - limits ocr3_1types.ReportingPluginLimits + config ocr3_1config.PublicConfig } var _ protocol.KeyValueDatabaseReadTransaction = &SemanticOCR3_1KeyValueDatabaseReadTransaction{} @@ -468,8 +462,8 @@ func (s *SemanticOCR3_1KeyValueDatabaseReadTransaction) Discard() { } func (s *SemanticOCR3_1KeyValueDatabaseReadTransaction) Read(key []byte) ([]byte, error) { - if !(len(key) <= ocr3_1types.MaxMaxKeyValueKeyLength) { - return nil, fmt.Errorf("key length %d exceeds maximum %d", len(key), ocr3_1types.MaxMaxKeyValueKeyLength) + if !(len(key) <= ocr3_1types.MaxMaxKeyValueKeyBytes) { + return nil, fmt.Errorf("key length %d exceeds maximum %d", len(key), ocr3_1types.MaxMaxKeyValueKeyBytes) } return s.rawTransaction.Read(pluginPrefixedUnhashedKey(key)) } @@ -598,11 +592,11 @@ func (s *SemanticOCR3_1KeyValueDatabaseReadTransaction) ReadTreeSyncChunk( keyValues, truncated, err := jmt.ReadRange( s, s, - protocol.RootVersion(toSeqNr), + protocol.RootVersion(toSeqNr, s.config), startIndex, requestEndInclIndex, - protocol.MaxTreeSyncChunkKeysPlusValuesLength, - protocol.MaxTreeSyncChunkKeys, + s.config.GetMaxTreeSyncChunkKeysPlusValuesBytes(), + s.config.GetMaxTreeSyncChunkKeys(), ) if err != nil { return jmt.Digest{}, nil, nil, fmt.Errorf("failed to read range: %w", err) @@ -620,7 +614,7 @@ func (s *SemanticOCR3_1KeyValueDatabaseReadTransaction) ReadTreeSyncChunk( boundingLeaves, err = jmt.ProveSubrange( s, s, - protocol.RootVersion(toSeqNr), + protocol.RootVersion(toSeqNr, s.config), startIndex, endInclIndex, ) @@ -669,17 +663,17 @@ func (s *SemanticOCR3_1KeyValueDatabaseReadWriteTransaction) VerifyAndWriteTreeS boundingLeaves []jmt.BoundingLeaf, keyValues []protocol.KeyValuePair, ) (protocol.VerifyAndWriteTreeSyncChunkResult, error) { - if len(keyValues) > protocol.MaxTreeSyncChunkKeys { + if len(keyValues) > s.config.GetMaxTreeSyncChunkKeys() { return protocol.VerifyAndWriteTreeSyncChunkResultByzantine, fmt.Errorf("too many leaves: %d > %d", - len(keyValues), protocol.MaxTreeSyncChunkKeys) + len(keyValues), s.config.GetMaxTreeSyncChunkKeys()) } var byteBudget int for _, kv := range keyValues { byteBudget += len(kv.Key) + len(kv.Value) } - if byteBudget > protocol.MaxTreeSyncChunkKeysPlusValuesLength { + if byteBudget > s.config.GetMaxTreeSyncChunkKeysPlusValuesBytes() { return protocol.VerifyAndWriteTreeSyncChunkResultByzantine, fmt.Errorf("chunk exceeds byte limit: %d > %d", - byteBudget, protocol.MaxTreeSyncChunkKeysPlusValuesLength) + byteBudget, s.config.GetMaxTreeSyncChunkKeysPlusValuesBytes()) } prevIdx := startIndex @@ -720,8 +714,8 @@ func (s *SemanticOCR3_1KeyValueDatabaseReadWriteTransaction) VerifyAndWriteTreeS s, s, s, - protocol.RootVersion(targetSeqNr), - protocol.RootVersion(targetSeqNr), + protocol.RootVersion(targetSeqNr, s.config), + protocol.RootVersion(targetSeqNr, s.config), keyValues, ) if err != nil { @@ -741,7 +735,7 @@ func (s *SemanticOCR3_1KeyValueDatabaseReadWriteTransaction) VerifyAndWriteTreeS rootDigest, err := jmt.ReadRootDigest( s, s, - protocol.RootVersion(targetSeqNr), + protocol.RootVersion(targetSeqNr, s.config), ) if err != nil { return protocol.VerifyAndWriteTreeSyncChunkResultUnrelatedError, fmt.Errorf("failed to read root digest: %w", err) @@ -761,7 +755,7 @@ func (s *SemanticOCR3_1KeyValueDatabaseReadTransaction) ReadBlobPayload(blobDige if blobMeta == nil { return nil, nil } - if slices.Contains(blobMeta.ChunksHave, false) { + if slices.Contains(blobMeta.ChunkHaves, false) { return nil, fmt.Errorf("blob has missing chunks") } @@ -790,7 +784,7 @@ func (s *SemanticOCR3_1KeyValueDatabaseReadTransaction) ReadBlobPayload(blobDige return nil, fmt.Errorf("error reading value for key %s: %w", key, err) } - expectedChunkSize := min(protocol.BlobChunkSize, residualLength) + expectedChunkSize := min(uint64(s.config.GetBlobChunkBytes()), residualLength) actualChunkSize := uint64(len(value)) if actualChunkSize != expectedChunkSize { return nil, fmt.Errorf("actual chunk size %v != expected chunk size %v", actualChunkSize, expectedChunkSize) @@ -873,7 +867,15 @@ func (s *SemanticOCR3_1KeyValueDatabaseReadWriteTransaction) WriteStaleNode(stal } func (s *SemanticOCR3_1KeyValueDatabaseReadWriteTransaction) DeleteStaleNodes(maxStaleSinceVersion jmt.Version, maxItems int) (done bool, err error) { - staleIndexNodeKeys, more, err := s.partialInclusiveRangeKeys(staleKeyWithStaleSinceVersionBase(0), staleKeyWithStaleSinceVersionBase(maxStaleSinceVersion), maxItems) + if maxStaleSinceVersion+1 < maxStaleSinceVersion { + return false, fmt.Errorf("maxStaleSinceVersion overflow") + } + + staleIndexNodeKeys, more, err := s.partialExclusiveRangeKeys( + staleKeyWithStaleSinceVersionBase(0), + staleKeyWithStaleSinceVersionBase(maxStaleSinceVersion+1), + maxItems, + ) if err != nil { return false, fmt.Errorf("failed to range: %w", err) } @@ -937,6 +939,29 @@ func (s *SemanticOCR3_1KeyValueDatabaseReadWriteTransaction) DeleteBlobMeta(blob return s.rawTransaction.Delete(blobMetaPrefixKey(blobDigest)) } +func (s *SemanticOCR3_1KeyValueDatabaseReadTransaction) ReadBlobQuotaStats(blobQuotaStatsType protocol.BlobQuotaStatsType, submitter commontypes.OracleID) (protocol.BlobQuotaStats, error) { + statsBytes, err := s.rawTransaction.Read(blobQuotaStatsPrefixKey(blobQuotaStatsType, submitter)) + if err != nil { + return protocol.BlobQuotaStats{}, fmt.Errorf("error reading blob quota stats for %s/%d: %w", blobQuotaStatsType, submitter, err) + } + if statsBytes == nil { + return protocol.BlobQuotaStats{}, nil + } + blobQuotaStats, err := serialization.DeserializeBlobQuotaStats(statsBytes) + if err != nil { + return protocol.BlobQuotaStats{}, fmt.Errorf("error unmarshaling blob quota stats for %s/%d: %w", blobQuotaStatsType, submitter, err) + } + return blobQuotaStats, nil +} + +func (s *SemanticOCR3_1KeyValueDatabaseReadWriteTransaction) WriteBlobQuotaStats(blobQuotaStatsType protocol.BlobQuotaStatsType, submitter commontypes.OracleID, blobQuotaStats protocol.BlobQuotaStats) error { + statsBytes, err := serialization.SerializeBlobQuotaStats(blobQuotaStats) + if err != nil { + return fmt.Errorf("error marshaling blob quota stats for %s/%d: %w", blobQuotaStatsType, submitter, err) + } + return s.rawTransaction.Write(blobQuotaStatsPrefixKey(blobQuotaStatsType, submitter), statsBytes) +} + func (s *SemanticOCR3_1KeyValueDatabaseReadTransaction) ReadStaleBlobIndex(maxStaleSinceSeqNr uint64, limit int) ([]protocol.StaleBlob, error) { it := s.rawTransaction.Range(staleBlobIndexPrefixKey(protocol.StaleBlob{0, blobtypes.BlobDigest{}}), staleBlobIndexPrefixKey(protocol.StaleBlob{maxStaleSinceSeqNr + 1, blobtypes.BlobDigest{}})) defer it.Close() @@ -967,15 +992,96 @@ func (s *SemanticOCR3_1KeyValueDatabaseReadWriteTransaction) DeleteStaleBlobInde return s.rawTransaction.Delete(staleBlobIndexPrefixKey(staleBlob)) } +func (s *SemanticOCR3_1KeyValueDatabaseReadTransaction) ReadReportsPlusPrecursor(seqNr uint64, reportsPlusPrecursorDigest protocol.ReportsPlusPrecursorDigest) (*ocr3_1types.ReportsPlusPrecursor, error) { + reportsPlusPrecursor, err := s.rawTransaction.Read(reportsPlusPrecursorKey(seqNr, reportsPlusPrecursorDigest)) + if err != nil { + return nil, fmt.Errorf("error reading reports plus precursor: %w", err) + } + if reportsPlusPrecursor == nil { + return nil, nil + } + return util.PointerTo(ocr3_1types.ReportsPlusPrecursor(reportsPlusPrecursor)), nil +} + +func (s *SemanticOCR3_1KeyValueDatabaseReadWriteTransaction) WriteReportsPlusPrecursor(seqNr uint64, reportsPlusPrecursorDigest protocol.ReportsPlusPrecursorDigest, reportsPlusPrecursor ocr3_1types.ReportsPlusPrecursor) error { + return s.rawTransaction.Write(reportsPlusPrecursorKey(seqNr, reportsPlusPrecursorDigest), reportsPlusPrecursor) +} + +func (s *SemanticOCR3_1KeyValueDatabaseReadWriteTransaction) DeleteReportsPlusPrecursors(minSeqNrToKeep uint64, maxItems int) (done bool, err error) { + keys, more, err := s.partialExclusiveRangeKeys(reportsPlusPrecursorKey(0, protocol.ReportsPlusPrecursorDigest{}), reportsPlusPrecursorKey(minSeqNrToKeep, protocol.ReportsPlusPrecursorDigest{}), maxItems) + if err != nil { + return false, fmt.Errorf("failed to range: %w", err) + } + for _, key := range keys { + if err := s.rawTransaction.Delete(key); err != nil { + return false, fmt.Errorf("failed to delete key %s: %w", key, err) + } + } + return !more, nil +} + +func (s *SemanticOCR3_1KeyValueDatabaseReadTransaction) ReadUnattestedStateTransitionBlock(seqNr uint64, stateTransitionInputsDigest protocol.StateTransitionInputsDigest) (*protocol.StateTransitionBlock, error) { + unattestedStateTransitionBlockRaw, err := s.rawTransaction.Read(unattestedBlockKey(seqNr, stateTransitionInputsDigest)) + if err != nil { + return nil, fmt.Errorf("error reading unattested state transition block: %w", err) + } + if unattestedStateTransitionBlockRaw == nil { + return nil, nil + } + ret, err := serialization.DeserializeStateTransitionBlock(unattestedStateTransitionBlockRaw) + if err != nil { + return nil, fmt.Errorf("failed to deserialize unattested state transition block: %w", err) + } + return &ret, nil +} + +func (s *SemanticOCR3_1KeyValueDatabaseReadTransaction) ExistsUnattestedStateTransitionBlock(seqNr uint64, stateTransitionInputsDigest protocol.StateTransitionInputsDigest) (bool, error) { + keys, _, err := s.partialInclusiveRangeKeys( + unattestedBlockKey(seqNr, stateTransitionInputsDigest), + unattestedBlockKey(seqNr, stateTransitionInputsDigest), + 1, + ) + return len(keys) == 1, err +} + +func (s *SemanticOCR3_1KeyValueDatabaseReadWriteTransaction) WriteUnattestedStateTransitionBlock(seqNr uint64, stateTransitionInputsDigest protocol.StateTransitionInputsDigest, stb protocol.StateTransitionBlock) error { + unattestedStateTransitionBlockRaw, err := serialization.SerializeStateTransitionBlock(stb) + if err != nil { + return fmt.Errorf("failed to serialize unattested state transition block: %w", err) + } + return s.rawTransaction.Write(unattestedBlockKey(seqNr, stateTransitionInputsDigest), unattestedStateTransitionBlockRaw) +} + +func (s *SemanticOCR3_1KeyValueDatabaseReadWriteTransaction) DeleteUnattestedStateTransitionBlocks(maxSeqNrToDelete uint64, maxItems int) (done bool, err error) { + if maxSeqNrToDelete+1 < maxSeqNrToDelete { + return false, fmt.Errorf("maxSeqNrToDelete overflow") + } + + keys, more, err := s.partialExclusiveRangeKeys( + unattestedBlockKey(0, protocol.StateTransitionInputsDigest{}), + unattestedBlockKey(maxSeqNrToDelete+1, protocol.StateTransitionInputsDigest{}), + maxItems, + ) + for _, key := range keys { + if err := s.rawTransaction.Delete(key); err != nil { + return false, fmt.Errorf("failed to delete key %s: %w", key, err) + } + } + return !more, err +} + const ( - blockPrefix = "B|" - pluginPrefix = "P|" - blobChunkPrefix = "BC|" - blobMetaPrefix = "BM|" - staleBlobIndexPrefix = "BI|" - treeNodePrefix = "TN|" - treeRootPrefix = "TR|" - treeStaleNodePrefix = "TSN|" + blockPrefix = "B|" + pluginPrefix = "P|" + blobChunkPrefix = "BC|" + blobMetaPrefix = "BM|" + blobQuotaStatsPrefix = "BQS|" + staleBlobIndexPrefix = "BI|" + treeNodePrefix = "TN|" + treeRootPrefix = "TR|" + treeStaleNodePrefix = "TSN|" + reportsPlusPrecursorPrefix = "RP|" + unattestedBlockPrefix = "UB|" treeSyncStatusKey = "TSS" highestCommittedSeqNrKey = "HCS" @@ -1029,6 +1135,11 @@ func blobMetaPrefixKey(blobDigest protocol.BlobDigest) []byte { return append([]byte(blobMetaPrefix), blobDigest[:]...) } +func blobQuotaStatsPrefixKey(blobQuotaStatsType protocol.BlobQuotaStatsType, submitter commontypes.OracleID) []byte { + base := append([]byte(blobQuotaStatsPrefix), []byte(blobQuotaStatsType)...) + return append(base, []byte(fmt.Sprintf("%d", submitter))...) +} + // ───────────────────────── meta ──────────────────────────── func rootKey(version uint64) []byte { @@ -1093,17 +1204,39 @@ func deserializeStaleBlobIndexKey(enc []byte) (protocol.StaleBlob, error) { return protocol.StaleBlob{staleSinceSeqNr, blobDigest}, nil } +// ────────────────────────── reports plus precursor ─────────────────────────── + +func reportsPlusPrecursorKey(seqNr uint64, reportsPlusPrecursorDigest protocol.ReportsPlusPrecursorDigest) []byte { + base := []byte(reportsPlusPrecursorPrefix) + base = append(base, encodeBigEndianUint64(seqNr)...) + base = append(base, reportsPlusPrecursorDigest[:]...) + return base +} + +// ────────────────────────── unattested blocks ─────────────────────────── + +func unattestedBlockKey(seqNr uint64, stateTransitionInputsDigest protocol.StateTransitionInputsDigest) []byte { + base := []byte(unattestedBlockPrefix) + base = append(base, encodeBigEndianUint64(seqNr)...) + base = append(base, stateTransitionInputsDigest[:]...) + return base +} + type limitCheckWriteSet struct { m map[string][]byte + keys int + keysLimit int keysPlusValuesLength int keysPlusValuesLengthLimit int } -func newLimitCheckWriteSet(keysPlusValuesLengthLimit int) *limitCheckWriteSet { +func newLimitCheckWriteSet(limits ocr3_1types.ReportingPluginLimits) *limitCheckWriteSet { return &limitCheckWriteSet{ make(map[string][]byte), 0, - keysPlusValuesLengthLimit, + limits.MaxKeyValueModifiedKeys, + 0, + limits.MaxKeyValueModifiedKeysPlusValuesBytes, } } @@ -1113,11 +1246,22 @@ func (l *limitCheckWriteSet) modify(key []byte, value []byte) error { if prevValue, ok := l.m[string(key)]; ok { add = len(value) sub = len(prevValue) + + // key already in write set, no change to l.keys } else { if len(key)+len(value) < len(key) { return fmt.Errorf("key + value length overflow") } add = len(key) + len(value) + + // new key being added + if l.keys+1 < l.keys { + return fmt.Errorf("keys overflow") + } + if l.keys+1 > l.keysLimit { + return fmt.Errorf("keys %d exceed limit %d", l.keys+1, l.keysLimit) + } + l.keys++ } keysPlusValuesLengthMinusExistingValue := l.keysPlusValuesLength - sub diff --git a/offchainreporting2plus/internal/shim/ocr3_1_reporting_plugin.go b/offchainreporting2plus/internal/shim/ocr3_1_reporting_plugin.go index b8544cab..49bace0f 100644 --- a/offchainreporting2plus/internal/shim/ocr3_1_reporting_plugin.go +++ b/offchainreporting2plus/internal/shim/ocr3_1_reporting_plugin.go @@ -26,8 +26,8 @@ func (rp LimitCheckOCR3_1ReportingPlugin[RI]) Query(ctx context.Context, seqNr u if err != nil { return nil, err } - if !(len(query) <= rp.Limits.MaxQueryLength) { - return nil, fmt.Errorf("LimitCheckOCR3_1Plugin: underlying plugin returned oversize query (%v vs %v)", len(query), rp.Limits.MaxQueryLength) + if !(len(query) <= rp.Limits.MaxQueryBytes) { + return nil, fmt.Errorf("LimitCheckOCR3_1Plugin: underlying plugin returned oversize query (%v vs %v)", len(query), rp.Limits.MaxQueryBytes) } return query, nil } @@ -41,8 +41,8 @@ func (rp LimitCheckOCR3_1ReportingPlugin[RI]) Observation(ctx context.Context, s if err != nil { return nil, err } - if !(len(observation) <= rp.Limits.MaxObservationLength) { - return nil, fmt.Errorf("LimitCheckOCR3_1Plugin: underlying plugin returned oversize observation (%v vs %v)", len(observation), rp.Limits.MaxObservationLength) + if !(len(observation) <= rp.Limits.MaxObservationBytes) { + return nil, fmt.Errorf("LimitCheckOCR3_1Plugin: underlying plugin returned oversize observation (%v vs %v)", len(observation), rp.Limits.MaxObservationBytes) } return observation, nil } @@ -57,8 +57,8 @@ func (rp LimitCheckOCR3_1ReportingPlugin[RI]) StateTransition(ctx context.Contex return nil, err } - if !(len(reportsPlusPrecursor) <= rp.Limits.MaxReportsPlusPrecursorLength) { - return nil, fmt.Errorf("LimitCheckOCR3_1Plugin: underlying plugin returned oversize reports precursor (%v vs %v)", len(reportsPlusPrecursor), rp.Limits.MaxReportsPlusPrecursorLength) + if !(len(reportsPlusPrecursor) <= rp.Limits.MaxReportsPlusPrecursorBytes) { + return nil, fmt.Errorf("LimitCheckOCR3_1Plugin: underlying plugin returned oversize reports precursor (%v vs %v)", len(reportsPlusPrecursor), rp.Limits.MaxReportsPlusPrecursorBytes) } return reportsPlusPrecursor, nil } @@ -76,8 +76,8 @@ func (rp LimitCheckOCR3_1ReportingPlugin[RI]) Reports(ctx context.Context, seqNr return nil, fmt.Errorf("LimitCheckOCR3_1Plugin: underlying plugin returned too many reports (%v vs %v)", len(reports), rp.Limits.MaxReportCount) } for i, reportPlus := range reports { - if !(len(reportPlus.ReportWithInfo.Report) <= rp.Limits.MaxReportLength) { - return nil, fmt.Errorf("LimitCheckOCR3_1Plugin: underlying plugin returned oversize report at index %v (%v vs %v)", i, len(reportPlus.ReportWithInfo.Report), rp.Limits.MaxReportLength) + if !(len(reportPlus.ReportWithInfo.Report) <= rp.Limits.MaxReportBytes) { + return nil, fmt.Errorf("LimitCheckOCR3_1Plugin: underlying plugin returned oversize report at index %v (%v vs %v)", i, len(reportPlus.ReportWithInfo.Report), rp.Limits.MaxReportBytes) } } return reports, nil diff --git a/offchainreporting2plus/internal/shim/ocr3_1_serializing_endpoint.go b/offchainreporting2plus/internal/shim/ocr3_1_serializing_endpoint.go index 85349d25..0d0f686c 100644 --- a/offchainreporting2plus/internal/shim/ocr3_1_serializing_endpoint.go +++ b/offchainreporting2plus/internal/shim/ocr3_1_serializing_endpoint.go @@ -9,7 +9,7 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/smartcontractkit/libocr/commontypes" "github.com/smartcontractkit/libocr/internal/loghelper" - "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3config" + "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config" "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/managed/limits" "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/ocr3_1/protocol" "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/ocr3_1/serialization" @@ -26,7 +26,7 @@ type OCR3_1SerializingEndpoint[RI any] struct { logger commontypes.Logger metrics *serializingEndpointMetrics pluginLimits ocr3_1types.ReportingPluginLimits - publicConfig ocr3config.PublicConfig + publicConfig ocr3_1config.PublicConfig serializedLengthLimits limits.OCR3_1SerializedLengthLimits mutex sync.Mutex @@ -49,7 +49,7 @@ func NewOCR3_1SerializingEndpoint[RI any]( logger commontypes.Logger, metricsRegisterer prometheus.Registerer, pluginLimits ocr3_1types.ReportingPluginLimits, - publicConfig ocr3config.PublicConfig, + publicConfig ocr3_1config.PublicConfig, serializedLengthLimits limits.OCR3_1SerializedLengthLimits, ) *OCR3_1SerializingEndpoint[RI] { return &OCR3_1SerializingEndpoint[RI]{ @@ -94,7 +94,7 @@ func (n *OCR3_1SerializingEndpoint[RI]) sendTelemetry(t *serialization.Telemetry } func (n *OCR3_1SerializingEndpoint[RI]) toOutboundBinaryMessage(msg protocol.Message[RI]) (types.OutboundBinaryMessage, *serialization.MessageWrapper) { - if !msg.CheckSize(n.publicConfig.N(), n.publicConfig.F, n.pluginLimits, n.maxSigLen) { + if !msg.CheckSize(n.publicConfig.N(), n.publicConfig.F, n.pluginLimits, n.maxSigLen, n.publicConfig) { n.logger.Error("OCR3_1SerializingEndpoint: Dropping outgoing message because it fails size check", commontypes.LogFields{ "limits": n.pluginLimits, }) @@ -130,9 +130,9 @@ func (n *OCR3_1SerializingEndpoint[RI]) toOutboundBinaryMessage(msg protocol.Mes return types.OutboundBinaryMessagePlain{payload, types.BinaryMessagePriorityDefault}, pbm case protocol.MessageReportSignatures[RI]: return types.OutboundBinaryMessagePlain{payload, types.BinaryMessagePriorityDefault}, pbm - case protocol.MessageCertifiedCommitRequest[RI]: + case protocol.MessageReportsPlusPrecursorRequest[RI]: return types.OutboundBinaryMessagePlain{payload, types.BinaryMessagePriorityDefault}, pbm - case protocol.MessageCertifiedCommit[RI]: + case protocol.MessageReportsPlusPrecursor[RI]: return types.OutboundBinaryMessagePlain{payload, types.BinaryMessagePriorityDefault}, pbm case protocol.MessageStateSyncSummary[RI]: return types.OutboundBinaryMessagePlain{payload, types.BinaryMessagePriorityLow}, pbm @@ -140,7 +140,7 @@ func (n *OCR3_1SerializingEndpoint[RI]) toOutboundBinaryMessage(msg protocol.Mes return types.OutboundBinaryMessageRequest{ types.SingleUseSizedLimitedResponsePolicy{ n.serializedLengthLimits.MaxLenMsgBlockSyncResponse, - time.Now().Add(protocol.DeltaMaxBlockSyncRequest), + msg.RequestInfo.ExpiryTimestamp, }, payload, types.BinaryMessagePriorityLow, @@ -151,7 +151,7 @@ func (n *OCR3_1SerializingEndpoint[RI]) toOutboundBinaryMessage(msg protocol.Mes return types.OutboundBinaryMessageRequest{ types.SingleUseSizedLimitedResponsePolicy{ n.serializedLengthLimits.MaxLenMsgTreeSyncChunkResponse, - time.Now().Add(protocol.DeltaMaxTreeSyncRequest), + msg.RequestInfo.ExpiryTimestamp, }, payload, types.BinaryMessagePriorityLow, @@ -243,13 +243,13 @@ func (n *OCR3_1SerializingEndpoint[RI]) fromInboundBinaryMessage(inboundBinaryMe if ibm, ok := inboundBinaryMessage.(types.InboundBinaryMessagePlain); !ok || ibm.Priority != types.BinaryMessagePriorityDefault { return protocol.MessageReportSignatures[RI]{}, pbm, fmt.Errorf("wrong type or priority for MessageReportSignatures") } - case protocol.MessageCertifiedCommitRequest[RI]: + case protocol.MessageReportsPlusPrecursorRequest[RI]: if ibm, ok := inboundBinaryMessage.(types.InboundBinaryMessagePlain); !ok || ibm.Priority != types.BinaryMessagePriorityDefault { - return protocol.MessageCertifiedCommitRequest[RI]{}, pbm, fmt.Errorf("wrong type or priority for MessageCertifiedCommitRequest") + return protocol.MessageReportsPlusPrecursorRequest[RI]{}, pbm, fmt.Errorf("wrong type or priority for MessageReportsPlusPrecursorRequest") } - case protocol.MessageCertifiedCommit[RI]: + case protocol.MessageReportsPlusPrecursor[RI]: if ibm, ok := inboundBinaryMessage.(types.InboundBinaryMessagePlain); !ok || ibm.Priority != types.BinaryMessagePriorityDefault { - return protocol.MessageCertifiedCommit[RI]{}, pbm, fmt.Errorf("wrong type or priority for MessageCertifiedCommit") + return protocol.MessageReportsPlusPrecursor[RI]{}, pbm, fmt.Errorf("wrong type or priority for MessageReportsPlusPrecursor") } case protocol.MessageBlockSyncRequest[RI]: if ibm, ok := inboundBinaryMessage.(types.InboundBinaryMessageRequest); !ok || ibm.Priority != types.BinaryMessagePriorityLow { @@ -289,7 +289,7 @@ func (n *OCR3_1SerializingEndpoint[RI]) fromInboundBinaryMessage(inboundBinaryMe } } - if !m.CheckSize(n.publicConfig.N(), n.publicConfig.F, n.pluginLimits, n.maxSigLen) { + if !m.CheckSize(n.publicConfig.N(), n.publicConfig.F, n.pluginLimits, n.maxSigLen, n.publicConfig) { return nil, nil, fmt.Errorf("message failed size check") } diff --git a/offchainreporting2plus/ocr3_1confighelper/ocr3_1confighelper.go b/offchainreporting2plus/ocr3_1confighelper/ocr3_1confighelper.go new file mode 100644 index 00000000..ddf20ec2 --- /dev/null +++ b/offchainreporting2plus/ocr3_1confighelper/ocr3_1confighelper.go @@ -0,0 +1,434 @@ +package ocr3_1confighelper + +import ( + "crypto/rand" + "fmt" + "time" + + "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" + "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config" + "github.com/smartcontractkit/libocr/offchainreporting2plus/internal/config/ocr3_1config" + "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "golang.org/x/crypto/curve25519" +) + +// PublicConfig is identical to the internal type [ocr3_1config.PublicConfig]. See +// the documentation there for details. We intentionally duplicate the internal +// type to make potential future internal modifications easier. +type PublicConfig struct { + OracleIdentities []confighelper.OracleIdentity + F int + + // pacemaker + + DeltaProgress time.Duration + DeltaResend *time.Duration + + // outcome generation + + DeltaInitial *time.Duration + DeltaRound time.Duration + DeltaGrace time.Duration + RMax uint64 + + // report attestation + + DeltaReportsPlusPrecursorRequest *time.Duration + + // transmission + + DeltaStage time.Duration + S []int + + // state sync + + DeltaStateSyncSummaryInterval *time.Duration + + // block sync + + DeltaBlockSyncMinRequestToSameOracleInterval *time.Duration + DeltaBlockSyncResponseTimeout *time.Duration + MaxBlocksPerBlockSyncResponse *int + MaxParallelRequestedBlocks *uint64 + + // tree sync + + DeltaTreeSyncMinRequestToSameOracleInterval *time.Duration + DeltaTreeSyncResponseTimeout *time.Duration + MaxTreeSyncChunkKeys *int + MaxTreeSyncChunkKeysPlusValuesBytes *int + MaxParallelTreeSyncChunkFetches *int + + // snapshotting + + SnapshotInterval *uint64 + MaxHistoricalSnapshotsRetained *uint64 + + // blobs + + DeltaBlobOfferMinRequestToSameOracleInterval *time.Duration + DeltaBlobOfferResponseTimeout *time.Duration + DeltaBlobBroadcastGrace *time.Duration + DeltaBlobChunkMinRequestToSameOracleInterval *time.Duration + DeltaBlobChunkResponseTimeout *time.Duration + BlobChunkBytes *int + + // reporting plugin + + ReportingPluginConfig []byte + OnchainConfig []byte + + MaxDurationInitialization time.Duration + WarnDurationQuery time.Duration + WarnDurationObservation time.Duration + WarnDurationValidateObservation time.Duration + WarnDurationObservationQuorum time.Duration + WarnDurationStateTransition time.Duration + WarnDurationCommitted time.Duration + MaxDurationShouldAcceptAttestedReport time.Duration + MaxDurationShouldTransmitAcceptedReport time.Duration + + ConfigDigest types.ConfigDigest +} + +func (pc PublicConfig) N() int { + return len(pc.OracleIdentities) +} + +type CheckPublicConfigLevel string + +const ( + CheckPublicConfigLevelDefault CheckPublicConfigLevel = "" + CheckPublicConfigLevelDangerInsaneForProduction CheckPublicConfigLevel = "danger_insane_for_production" +) + +func (c CheckPublicConfigLevel) shouldSkipInsaneForProductionChecks() bool { + switch c { + case CheckPublicConfigLevelDefault: + return false + case CheckPublicConfigLevelDangerInsaneForProduction: + return true + default: + panic(fmt.Sprintf("invalid checkPublicConfigLevel: %v", c)) + } +} + +func PublicConfigFromContractConfig(checkPublicConfigLevel CheckPublicConfigLevel, change types.ContractConfig) (PublicConfig, error) { + internalPublicConfig, err := ocr3_1config.PublicConfigFromContractConfig(checkPublicConfigLevel.shouldSkipInsaneForProductionChecks(), change) + if err != nil { + return PublicConfig{}, err + } + identities := []confighelper.OracleIdentity{} + for _, internalIdentity := range internalPublicConfig.OracleIdentities { + identities = append(identities, confighelper.OracleIdentity{ + internalIdentity.OffchainPublicKey, + internalIdentity.OnchainPublicKey, + internalIdentity.PeerID, + internalIdentity.TransmitAccount, + }) + } + return PublicConfig{ + identities, + internalPublicConfig.F, + + // outcome generation + + internalPublicConfig.DeltaProgress, + internalPublicConfig.DeltaResend, + internalPublicConfig.DeltaInitial, + internalPublicConfig.DeltaRound, + internalPublicConfig.DeltaGrace, + internalPublicConfig.RMax, + + // report attestation + + internalPublicConfig.DeltaReportsPlusPrecursorRequest, + + // transmission + + internalPublicConfig.DeltaStage, + internalPublicConfig.S, + + // state sync + + internalPublicConfig.DeltaStateSyncSummaryInterval, + + // block sync + + internalPublicConfig.DeltaBlockSyncMinRequestToSameOracleInterval, + internalPublicConfig.DeltaBlockSyncResponseTimeout, + internalPublicConfig.MaxBlocksPerBlockSyncResponse, + internalPublicConfig.MaxParallelRequestedBlocks, + + // tree sync + + internalPublicConfig.DeltaTreeSyncMinRequestToSameOracleInterval, + internalPublicConfig.DeltaTreeSyncResponseTimeout, + internalPublicConfig.MaxTreeSyncChunkKeys, + internalPublicConfig.MaxTreeSyncChunkKeysPlusValuesBytes, + internalPublicConfig.MaxParallelTreeSyncChunkFetches, + + // snapshotting + + internalPublicConfig.SnapshotInterval, + internalPublicConfig.MaxHistoricalSnapshotsRetained, + + // blobs + + internalPublicConfig.DeltaBlobOfferMinRequestToSameOracleInterval, + internalPublicConfig.DeltaBlobOfferResponseTimeout, + internalPublicConfig.DeltaBlobBroadcastGrace, + internalPublicConfig.DeltaBlobChunkMinRequestToSameOracleInterval, + internalPublicConfig.DeltaBlobChunkResponseTimeout, + internalPublicConfig.BlobChunkBytes, + + // reporting plugin + + internalPublicConfig.ReportingPluginConfig, + internalPublicConfig.OnchainConfig, + + internalPublicConfig.MaxDurationInitialization, + internalPublicConfig.WarnDurationQuery, + internalPublicConfig.WarnDurationObservation, + internalPublicConfig.WarnDurationValidateObservation, + internalPublicConfig.WarnDurationObservationQuorum, + internalPublicConfig.WarnDurationStateTransition, + internalPublicConfig.WarnDurationCommitted, + internalPublicConfig.MaxDurationShouldAcceptAttestedReport, + internalPublicConfig.MaxDurationShouldTransmitAcceptedReport, + internalPublicConfig.ConfigDigest, + }, nil +} + +// ContractSetConfigArgsForTests generates setConfig args for testing. Only use +// this for testing, *not* for production. +// See [ocr3_1config.PublicConfig] for documentation of the arguments. +func ContractSetConfigArgsForTests( + checkPublicConfigLevel CheckPublicConfigLevel, + oracles []confighelper.OracleIdentityExtra, + f int, + deltaProgress time.Duration, + deltaRound time.Duration, + deltaGrace time.Duration, + rMax uint64, + deltaStage time.Duration, + s []int, + reportingPluginConfig []byte, + onchainConfig []byte, + maxDurationInitialization time.Duration, + warnDurationQuery time.Duration, + warnDurationObservation time.Duration, + warnDurationValidateObservation time.Duration, + warnDurationObservationQuorum time.Duration, + warnDurationStateTransition time.Duration, + warnDurationCommitted time.Duration, + maxDurationShouldAcceptAttestedReport time.Duration, + maxDurationShouldTransmitAcceptedReport time.Duration, + // Optional configuration parameters + optionalConfig ContractSetConfigArgsOptionalConfig, +) ( + signers []types.OnchainPublicKey, + transmitters []types.Account, + f_ uint8, + onchainConfig_ []byte, + offchainConfigVersion uint64, + offchainConfig []byte, + err error, +) { + ephemeralSk := [curve25519.ScalarSize]byte{} + if _, err := rand.Read(ephemeralSk[:]); err != nil { + return nil, nil, 0, nil, 0, nil, err + } + + sharedSecret := [config.SharedSecretSize]byte{} + if _, err := rand.Read(sharedSecret[:]); err != nil { + return nil, nil, 0, nil, 0, nil, err + } + + return ContractSetConfigArgsDeterministic( + checkPublicConfigLevel, + ephemeralSk, + sharedSecret, + oracles, + f, + deltaProgress, + deltaRound, + deltaGrace, + rMax, + deltaStage, + s, + reportingPluginConfig, + onchainConfig, + maxDurationInitialization, + warnDurationQuery, + warnDurationObservation, + warnDurationValidateObservation, + warnDurationObservationQuorum, + warnDurationStateTransition, + warnDurationCommitted, + maxDurationShouldAcceptAttestedReport, + maxDurationShouldTransmitAcceptedReport, + optionalConfig, + ) +} + +// ContractSetConfigArgsOptionalConfig holds optional parameters +// for ContractSetConfigArgsDeterministic. +type ContractSetConfigArgsOptionalConfig struct { + DeltaResend *time.Duration + DeltaInitial *time.Duration + DeltaReportsPlusPrecursorRequest *time.Duration + + // state sync + DeltaStateSyncSummaryInterval *time.Duration + + // block sync + DeltaBlockSyncMinRequestToSameOracleInterval *time.Duration + DeltaBlockSyncResponseTimeout *time.Duration + MaxBlocksPerBlockSyncResponse *int + MaxParallelRequestedBlocks *uint64 + + // tree sync + DeltaTreeSyncMinRequestToSameOracleInterval *time.Duration + DeltaTreeSyncResponseTimeout *time.Duration + MaxTreeSyncChunkKeys *int + MaxTreeSyncChunkKeysPlusValuesBytes *int + MaxParallelTreeSyncChunkFetches *int + + // snapshotting + SnapshotInterval *uint64 + MaxHistoricalSnapshotsRetained *uint64 + + // blobs + DeltaBlobOfferMinRequestToSameOracleInterval *time.Duration + DeltaBlobOfferResponseTimeout *time.Duration + DeltaBlobBroadcastGrace *time.Duration + DeltaBlobChunkMinRequestToSameOracleInterval *time.Duration + DeltaBlobChunkResponseTimeout *time.Duration + BlobChunkBytes *int +} + +// This function may be used in production. If you use this as part of multisig +// tooling, make sure that the input parameters are identical across all +// signers. +// See [ocr3_1config.PublicConfig] for documentation of the arguments. +func ContractSetConfigArgsDeterministic( + checkPublicConfigLevel CheckPublicConfigLevel, + // The ephemeral secret key used to encrypt the shared secret + ephemeralSk [curve25519.ScalarSize]byte, + // A secret shared between all oracles, enabling them to derive pseudorandom + // leaders and transmitters. This is a low-value secret. An adversary who + // learns this secret can only determine which oracle will be + // leader/transmitter ahead of time, that's it. + sharedSecret [config.SharedSecretSize]byte, + // Check out the ocr3_1config package for documentation on the following args + oracles []confighelper.OracleIdentityExtra, + f int, + deltaProgress time.Duration, + deltaRound time.Duration, + deltaGrace time.Duration, + rMax uint64, + deltaStage time.Duration, + s []int, + reportingPluginConfig []byte, + onchainConfig []byte, + maxDurationInitialization time.Duration, + warnDurationQuery time.Duration, + warnDurationObservation time.Duration, + warnDurationValidateObservation time.Duration, + warnDurationObservationQuorum time.Duration, + warnDurationStateTransition time.Duration, + warnDurationCommitted time.Duration, + maxDurationShouldAcceptAttestedReport time.Duration, + maxDurationShouldTransmitAcceptedReport time.Duration, + // Optional configuration parameters + optionalConfig ContractSetConfigArgsOptionalConfig, +) ( + signers []types.OnchainPublicKey, + transmitters []types.Account, + f_ uint8, + onchainConfig_ []byte, + offchainConfigVersion uint64, + offchainConfig []byte, + err error, +) { + identities := []config.OracleIdentity{} + configEncryptionPublicKeys := []types.ConfigEncryptionPublicKey{} + for _, oracle := range oracles { + identities = append(identities, config.OracleIdentity{ + oracle.OffchainPublicKey, + oracle.OnchainPublicKey, + oracle.PeerID, + oracle.TransmitAccount, + }) + configEncryptionPublicKeys = append(configEncryptionPublicKeys, oracle.ConfigEncryptionPublicKey) + } + + sharedConfig := ocr3_1config.SharedConfig{ + ocr3_1config.PublicConfig{ + deltaProgress, + optionalConfig.DeltaResend, + optionalConfig.DeltaInitial, + deltaRound, + deltaGrace, + optionalConfig.DeltaReportsPlusPrecursorRequest, + deltaStage, + + // state sync + optionalConfig.DeltaStateSyncSummaryInterval, + + // block sync + optionalConfig.DeltaBlockSyncMinRequestToSameOracleInterval, + optionalConfig.DeltaBlockSyncResponseTimeout, + optionalConfig.MaxBlocksPerBlockSyncResponse, + optionalConfig.MaxParallelRequestedBlocks, + + // tree sync + optionalConfig.DeltaTreeSyncMinRequestToSameOracleInterval, + optionalConfig.DeltaTreeSyncResponseTimeout, + optionalConfig.MaxTreeSyncChunkKeys, + optionalConfig.MaxTreeSyncChunkKeysPlusValuesBytes, + optionalConfig.MaxParallelTreeSyncChunkFetches, + + // snapshotting + optionalConfig.SnapshotInterval, + optionalConfig.MaxHistoricalSnapshotsRetained, + + // blobs + optionalConfig.DeltaBlobOfferMinRequestToSameOracleInterval, + optionalConfig.DeltaBlobOfferResponseTimeout, + optionalConfig.DeltaBlobBroadcastGrace, + optionalConfig.DeltaBlobChunkMinRequestToSameOracleInterval, + optionalConfig.DeltaBlobChunkResponseTimeout, + optionalConfig.BlobChunkBytes, + + rMax, + s, + identities, + reportingPluginConfig, + maxDurationInitialization, + warnDurationQuery, + warnDurationObservation, + warnDurationValidateObservation, + warnDurationObservationQuorum, + warnDurationStateTransition, + warnDurationCommitted, + maxDurationShouldAcceptAttestedReport, + maxDurationShouldTransmitAcceptedReport, + f, + onchainConfig, + types.ConfigDigest{}, + }, + &sharedSecret, + } + + if err := ocr3_1config.CheckPublicConfig(checkPublicConfigLevel.shouldSkipInsaneForProductionChecks(), sharedConfig.PublicConfig); err != nil { + return nil, nil, 0, nil, 0, nil, fmt.Errorf("CheckPublicConfig: %w", err) + } + + return ocr3_1config.ContractSetConfigArgsFromSharedConfigDeterministic( + sharedConfig, + configEncryptionPublicKeys, + &ephemeralSk, + ) +} diff --git a/offchainreporting2plus/ocr3_1types/plugin.go b/offchainreporting2plus/ocr3_1types/plugin.go index aefc115f..4dbaf008 100644 --- a/offchainreporting2plus/ocr3_1types/plugin.go +++ b/offchainreporting2plus/ocr3_1types/plugin.go @@ -92,7 +92,7 @@ type KeyValueStateReadWriter interface { // expiration may occur for a number of reasons, including (1) shutdown of the // protocol instance, (2) the protocol's progression through epochs (whether // they're abandoned or completed successfully), and (3) timeout parameters. See -// the documentation on ocr3config.PublicConfig for more information on how +// the documentation on ocr3_1config.PublicConfig for more information on how // to configure timeouts. // // Many functions on the ReportingPlugin are marked as pure‡. This is because they may be @@ -220,6 +220,8 @@ type ReportingPlugin[RI any] interface { // it returns true for aos, it must also return true for any // superset of aos. // + // The AttributedObservations are guaranteed to be from distinct oracles. + // // The keyValueStateReader gives read access to the replicated KeyValueState // at the point after seqNr - 1 is committed. It must not be used outside the execution // of this function. (It's okay to use it anywhere in the call tree rooted at this function @@ -250,8 +252,9 @@ type ReportingPlugin[RI any] interface { // across the lifetime of a protocol instance. // // You may assume that the provided list of attributed observations has been - // (1) validated by ValidateObservation on each element, and (2) checked - // by ObservationQuorum to have reached quorum. + // (1) validated by ValidateObservation on each element, (2) checked + // by ObservationQuorum to have reached quorum, and (3) all observations are + // from distinct oracles. // // The keyValueStateReadWriter gives read and write access to the replicated KeyValueState // from the point after seqNr - 1 is committed. Writing to the keyValueStateReadWriter allows @@ -347,18 +350,19 @@ type ReportingPlugin[RI any] interface { const ( mib = 1024 * 1024 - MaxMaxQueryLength = mib / 2 - MaxMaxObservationLength = mib / 2 - MaxMaxReportsPlusPrecursorLength = 5 * mib - MaxMaxReportLength = 5 * mib - MaxMaxReportCount = 2000 + MaxMaxQueryBytes = mib / 2 + MaxMaxObservationBytes = mib / 2 + MaxMaxReportsPlusPrecursorBytes = 5 * mib + MaxMaxReportBytes = 5 * mib + MaxMaxReportCount = 2000 - MaxMaxKeyValueKeyLength = 1 * mib - MaxMaxKeyValueValueLength = 2 * mib + MaxMaxKeyValueKeyBytes = 1 * mib + MaxMaxKeyValueValueBytes = 2 * mib - MaxMaxKeyValueModifiedKeysPlusValuesLength = 10 * mib + MaxMaxKeyValueModifiedKeys = 10_000 + MaxMaxKeyValueModifiedKeysPlusValuesBytes = 10 * mib - MaxMaxBlobPayloadLength = 5 * mib + MaxMaxBlobPayloadBytes = 5 * mib ) // Limits for data returned by the ReportingPlugin. @@ -367,26 +371,38 @@ const ( // careful when changing these values, they could lead to different versions // of a ReportingPlugin being unable to communicate with each other. type ReportingPluginLimits struct { - MaxQueryLength int - MaxObservationLength int - MaxReportsPlusPrecursorLength int - MaxReportLength int - MaxReportCount int + MaxQueryBytes int + MaxObservationBytes int + MaxReportsPlusPrecursorBytes int + MaxReportBytes int + MaxReportCount int - // This limit concerns modifications to key-values inside the + // These limits concern modifications to key-values inside the // StateTransition method. Write(k, v) and Delete(k) count as modifications. // A modification that resets the value of a key to its original value at // the start of StateTransition will still count towards the limit. - MaxKeyValueModifiedKeysPlusValuesLength int - MaxBlobPayloadLength int + MaxKeyValueModifiedKeys int + MaxKeyValueModifiedKeysPlusValuesBytes int + + MaxBlobPayloadBytes int + MaxPerOracleUnexpiredBlobCumulativePayloadBytes int + MaxPerOracleUnexpiredBlobCount int +} + +//go-sumtype:decl ReportingPluginInfo - // Mandatory blob rate limits will be introduced in a future release. +type ReportingPluginInfo interface { + isReportingPluginInfo() } -type ReportingPluginInfo struct { +type ReportingPluginInfo1 struct { // Used for debugging purposes. Name string Limits ReportingPluginLimits } + +var _ ReportingPluginInfo = ReportingPluginInfo1{} + +func (ReportingPluginInfo1) isReportingPluginInfo() {} diff --git a/offchainreporting2plus/types/network.go b/offchainreporting2plus/types/network.go index 16620113..1d1bfcb8 100644 --- a/offchainreporting2plus/types/network.go +++ b/offchainreporting2plus/types/network.go @@ -25,10 +25,22 @@ type SingleUseSizedLimitedResponsePolicy struct { func (SingleUseSizedLimitedResponsePolicy) isResponsePolicy() {} +var ( + EmptyRequestHandleForOutboundRequest RequestHandle + EmptyRequestHandleForInboundResponse RequestHandle +) + type RequestHandle interface { MakeResponse(payload []byte) OutboundBinaryMessageResponse } +var EmptyRequestInfoForInboundRequest *RequestInfo + +type RequestInfo struct { + // If no response is received by this time, the request is considered timed out. + ExpiryTimestamp time.Time +} + type OutboundBinaryMessage interface { isOutboundBinaryMessage() GetPayload() []byte diff --git a/ragep2p/ragep2pnew/internal/overheadawareconn/overhead_aware_conn.go b/ragep2p/ragep2pnew/internal/overheadawareconn/overhead_aware_conn.go index 91d147cc..e2d4c2d4 100644 --- a/ragep2p/ragep2pnew/internal/overheadawareconn/overhead_aware_conn.go +++ b/ragep2p/ragep2pnew/internal/overheadawareconn/overhead_aware_conn.go @@ -99,7 +99,7 @@ func (r *OverheadAwareConn) AddDeliveredApplicationDataBytes(bytes int) error { readPostSetupRawBytesAttributableToDeliveredApplicationData := r.readPostSetupRawBytes - GenerouslyOverstimatedTLSReadAhead - if r.deliveredApplicationDataBytes*2 < readPostSetupRawBytesAttributableToDeliveredApplicationData { + if r.deliveredApplicationDataBytes*MaximumAllowedApplicationDataToRawFactor < readPostSetupRawBytesAttributableToDeliveredApplicationData { return fmt.Errorf("inbound read overhead on underlying TCP connection is too large, suspecting shenanigans: deliveredApplicationDataBytes=%d, readPostSetupRawBytes=%d, generouslyOverstimatedTLSReadAhead=%d", r.deliveredApplicationDataBytes, r.readPostSetupRawBytes, diff --git a/ragep2p/ragep2pnew/ragep2p.go b/ragep2p/ragep2pnew/ragep2p.go index d38eab1c..bb9a90e4 100644 --- a/ragep2p/ragep2pnew/ragep2p.go +++ b/ragep2p/ragep2pnew/ragep2p.go @@ -270,8 +270,12 @@ func remotePeerIDField(other types.PeerID) commontypes.LogFields { } // Caller should hold peersMu. -func (ho *Host) findOrCreatePeer(other types.PeerID) *peer { +func (ho *Host) findOrCreatePeer(other types.PeerID) (*peer, error) { if _, ok := ho.peers[other]; !ok { + if len(ho.peers) >= types.MaxPeersPerHost { + return nil, fmt.Errorf("cannot add peer %s because maximum number of peers %d has been reached", other, types.MaxPeersPerHost) + } + logger := ho.logger.MakeChild(remotePeerIDField(other)) metrics := newPeerMetrics(ho.metricsRegisterer, logger, ho.id, other) @@ -364,7 +368,7 @@ func (ho *Host) findOrCreatePeer(other types.PeerID) *peer { ) }) } - return ho.peers[other] + return ho.peers[other], nil } func peerLoop( @@ -461,6 +465,11 @@ func peerLoop( logger.Trace("Connection terminated, paused all streams", nil) case notification := <-chOtherStreamStateNotification: + if chConnTerminated == nil { + // connection is dead, ignore stale notification + break + } + logger.Trace("Received stream state notification", commontypes.LogFields{ "notification": notification, }) @@ -1027,7 +1036,10 @@ func (ho *Host) NewStream2( ho.peersMu.Lock() defer ho.peersMu.Unlock() - p := ho.findOrCreatePeer(other) + p, err := ho.findOrCreatePeer(other) + if err != nil { + return nil, err + } sid := internaltypes.MakeStreamID(ho.id, other, streamName) @@ -1110,12 +1122,12 @@ func authenticatedConnectionLoop( chSelfStreamStateNotification <-chan streamStateNotification, mux *muxer.Muxer, demux *demuxer.Demuxer, - chTerminated chan<- struct{}, + chConnTerminated chan<- struct{}, logger loghelper.LoggerWithContext, metrics *peerMetrics, ) { defer func() { - close(chTerminated) + close(chConnTerminated) logger.Info("authenticatedConnectionLoop: exited", nil) }() @@ -1595,5 +1607,6 @@ func incomingConnsRateLimit(durationBetweenDials time.Duration) ratelimit.Millit type Discoverer interface { Start(host ragep2pwrapper.Host, keyring types.PeerKeyring, logger loghelper.LoggerWithContext) error Close() error + // The order of the returned addresses matters because the addresses are tried in order. FindPeer(peer types.PeerID) ([]types.Address, error) } diff --git a/ragep2p/ragep2pnew/stream2.go b/ragep2p/ragep2pnew/stream2.go index a1a58bf6..059da443 100644 --- a/ragep2p/ragep2pnew/stream2.go +++ b/ragep2p/ragep2pnew/stream2.go @@ -133,8 +133,7 @@ func (st *stream2) UpdateLimits(limits Stream2Limits) error { } return nil case <-st.ctx.Done(): - - return fmt.Errorf("UpdateLimts: called after Stream internal context already expired") + return fmt.Errorf("stream already shut down, likely due to stream.Close() or host.Close()") } } @@ -180,6 +179,7 @@ func (st *stream2) Close() error { delete(host.peers, st.other) } case <-st.ctx.Done(): + return fmt.Errorf("stream already shut down, likely due to host.Close()") } return nil }() diff --git a/ragep2p/types/types.go b/ragep2p/types/types.go index 8799a4d7..a489e39e 100644 --- a/ragep2p/types/types.go +++ b/ragep2p/types/types.go @@ -140,6 +140,13 @@ type TokenBucketParams struct { Capacity uint32 } +// The maximum number of peers we can have across all concurrent streams on a host. +// The exact number is chosen arbitrarily. Better to have an arbitrary limit +// than no limit. +// If you are using ragedisco for peer discovery, also note the separate limit in +// ragedisco.MaxOracles. +const MaxPeersPerHost = 256 + const MaxStreamsPerPeer = 2_000 const MaxMessageLength = 1024 * 1024 * 1024 // 1 GiB. This must be smaller than INT32_MAX