Skip to content

Commit 736d232

Browse files
committed
Merge branch 'master' of https://github.com/onflow/flow-go into yurii/6493-skipping-blocks-too-far-in-future
2 parents 43930a7 + 243a5e3 commit 736d232

File tree

107 files changed

+2680
-2114
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

107 files changed

+2680
-2114
lines changed

Makefile

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# The short Git commit hash
22
SHORT_COMMIT := $(shell git rev-parse --short HEAD)
3+
BRANCH_NAME:=$(shell git rev-parse --abbrev-ref HEAD | tr '/' '-')
34
# The Git commit hash
45
COMMIT := $(shell git rev-parse HEAD)
56
# The tag of the current commit, otherwise empty
@@ -9,6 +10,9 @@ VERSION := $(shell git describe --tags --abbrev=2 --match "v*" --match "secure-c
910
# dynamically split up CI jobs into smaller jobs that can be run in parallel
1011
GO_TEST_PACKAGES := ./...
1112

13+
FLOW_GO_TAG := v0.28.15
14+
15+
1216
# Image tag: if image tag is not set, set it with version (or short commit if empty)
1317
ifeq (${IMAGE_TAG},)
1418
IMAGE_TAG := ${VERSION}
@@ -33,6 +37,7 @@ GOARCH := $(shell go env GOARCH)
3337
# The location of the k8s YAML files
3438
K8S_YAMLS_LOCATION_STAGING=./k8s/staging
3539

40+
3641
# docker container registry
3742
export CONTAINER_REGISTRY := gcr.io/flow-container-registry
3843
export DOCKER_BUILDKIT := 1
@@ -156,7 +161,7 @@ generate-mocks: install-mock-generators
156161
mockery --name '.*' --dir=engine/execution/computation/computer --case=underscore --output="./engine/execution/computation/computer/mock" --outpkg="mock"
157162
mockery --name '.*' --dir=engine/execution/state --case=underscore --output="./engine/execution/state/mock" --outpkg="mock"
158163
mockery --name '.*' --dir=engine/collection --case=underscore --output="./engine/collection/mock" --outpkg="mock"
159-
mockery --name '.*' --dir=engine/common --case=underscore --output="./engine/common/mock" --outpkg="mock"
164+
mockery --name 'complianceCore' --dir=engine/common/follower --exported --case=underscore --output="./engine/common/follower/mock" --outpkg="mock"
160165
mockery --name '.*' --dir=engine/common/follower/cache --case=underscore --output="./engine/common/follower/cache/mock" --outpkg="mock"
161166
mockery --name '.*' --dir=engine/consensus --case=underscore --output="./engine/consensus/mock" --outpkg="mock"
162167
mockery --name '.*' --dir=engine/consensus/approvals --case=underscore --output="./engine/consensus/approvals/mock" --outpkg="mock"
@@ -249,12 +254,12 @@ docker-ci-integration:
249254
docker-build-collection:
250255
docker build -f cmd/Dockerfile --build-arg TARGET=./cmd/collection --build-arg COMMIT=$(COMMIT) --build-arg VERSION=$(IMAGE_TAG) --build-arg GOARCH=$(GOARCH) --target production \
251256
--label "git_commit=${COMMIT}" --label "git_tag=${IMAGE_TAG}" \
252-
-t "$(CONTAINER_REGISTRY)/collection:latest" -t "$(CONTAINER_REGISTRY)/collection:$(SHORT_COMMIT)" -t "$(CONTAINER_REGISTRY)/collection:$(IMAGE_TAG)" .
257+
-t "$(CONTAINER_REGISTRY)/collection:latest" -t "$(CONTAINER_REGISTRY)/collection:$(SHORT_COMMIT)" -t "$(CONTAINER_REGISTRY)/collection:$(IMAGE_TAG)" -t "$(CONTAINER_REGISTRY)/collection:$(FLOW_GO_TAG)" .
253258

254259
.PHONY: docker-build-collection-without-netgo
255260
docker-build-collection-without-netgo:
256261
docker build -f cmd/Dockerfile --build-arg TAGS=relic --build-arg TARGET=./cmd/collection --build-arg COMMIT=$(COMMIT) --build-arg VERSION=$(IMAGE_TAG_NO_NETGO) --build-arg GOARCH=$(GOARCH) --target production \
257-
--label "git_commit=${COMMIT}" --label "git_tag=$(IMAGE_TAG_NO_NETGO)" -t "$(CONTAINER_REGISTRY)/collection:$(IMAGE_TAG_NO_NETGO)" .
262+
--label "git_commit=${COMMIT}" --label "git_tag=$(IMAGE_TAG_NO_NETGO)" -t "$(CONTAINER_REGISTRY)/collection:$(IMAGE_TAG_NO_NETGO)" .
258263

259264
.PHONY: docker-build-collection-debug
260265
docker-build-collection-debug:
@@ -265,7 +270,7 @@ docker-build-collection-debug:
265270
docker-build-consensus:
266271
docker build -f cmd/Dockerfile --build-arg TARGET=./cmd/consensus --build-arg COMMIT=$(COMMIT) --build-arg VERSION=$(IMAGE_TAG) --build-arg GOARCH=$(GOARCH) --target production \
267272
--label "git_commit=${COMMIT}" --label "git_tag=${IMAGE_TAG}" \
268-
-t "$(CONTAINER_REGISTRY)/consensus:latest" -t "$(CONTAINER_REGISTRY)/consensus:$(SHORT_COMMIT)" -t "$(CONTAINER_REGISTRY)/consensus:$(IMAGE_TAG)" .
273+
-t "$(CONTAINER_REGISTRY)/consensus:latest" -t "$(CONTAINER_REGISTRY)/consensus:$(SHORT_COMMIT)" -t "$(CONTAINER_REGISTRY)/consensus:$(IMAGE_TAG)" -t "$(CONTAINER_REGISTRY)/consensus:$(FLOW_GO_TAG)" .
269274

270275
.PHONY: docker-build-consensus-without-netgo
271276
docker-build-consensus-without-netgo:
@@ -281,7 +286,7 @@ docker-build-consensus-debug:
281286
docker-build-execution:
282287
docker build -f cmd/Dockerfile --build-arg TARGET=./cmd/execution --build-arg COMMIT=$(COMMIT) --build-arg VERSION=$(IMAGE_TAG) --build-arg GOARCH=$(GOARCH) --target production \
283288
--label "git_commit=${COMMIT}" --label "git_tag=${IMAGE_TAG}" \
284-
-t "$(CONTAINER_REGISTRY)/execution:latest" -t "$(CONTAINER_REGISTRY)/execution:$(SHORT_COMMIT)" -t "$(CONTAINER_REGISTRY)/execution:$(IMAGE_TAG)" .
289+
-t "$(CONTAINER_REGISTRY)/execution:latest" -t "$(CONTAINER_REGISTRY)/execution:$(SHORT_COMMIT)" -t "$(CONTAINER_REGISTRY)/execution:$(IMAGE_TAG)" -t "$(CONTAINER_REGISTRY)/execution:$(FLOW_GO_TAG)" .
285290

286291
.PHONY: docker-build-execution-without-netgo
287292
docker-build-execution-without-netgo:
@@ -307,7 +312,7 @@ docker-build-execution-corrupt:
307312
docker-build-verification:
308313
docker build -f cmd/Dockerfile --build-arg TARGET=./cmd/verification --build-arg COMMIT=$(COMMIT) --build-arg VERSION=$(IMAGE_TAG) --build-arg GOARCH=$(GOARCH) --target production \
309314
--label "git_commit=${COMMIT}" --label "git_tag=${IMAGE_TAG}" \
310-
-t "$(CONTAINER_REGISTRY)/verification:latest" -t "$(CONTAINER_REGISTRY)/verification:$(SHORT_COMMIT)" -t "$(CONTAINER_REGISTRY)/verification:$(IMAGE_TAG)" .
315+
-t "$(CONTAINER_REGISTRY)/verification:latest" -t "$(CONTAINER_REGISTRY)/verification:$(SHORT_COMMIT)" -t "$(CONTAINER_REGISTRY)/verification:$(IMAGE_TAG)" -t "$(CONTAINER_REGISTRY)/verification:$(FLOW_GO_TAG)" .
311316

312317
.PHONY: docker-build-verification-without-netgo
313318
docker-build-verification-without-netgo:
@@ -333,7 +338,7 @@ docker-build-verification-corrupt:
333338
docker-build-access:
334339
docker build -f cmd/Dockerfile --build-arg TARGET=./cmd/access --build-arg COMMIT=$(COMMIT) --build-arg VERSION=$(IMAGE_TAG) --build-arg GOARCH=$(GOARCH) --target production \
335340
--label "git_commit=${COMMIT}" --label "git_tag=${IMAGE_TAG}" \
336-
-t "$(CONTAINER_REGISTRY)/access:latest" -t "$(CONTAINER_REGISTRY)/access:$(SHORT_COMMIT)" -t "$(CONTAINER_REGISTRY)/access:$(IMAGE_TAG)" .
341+
-t "$(CONTAINER_REGISTRY)/access:latest" -t "$(CONTAINER_REGISTRY)/access:$(SHORT_COMMIT)" -t "$(CONTAINER_REGISTRY)/access:$(IMAGE_TAG)" -t "$(CONTAINER_REGISTRY)/access:$(FLOW_GO_TAG)" .
337342

338343
.PHONY: docker-build-access-without-netgo
339344
docker-build-access-without-netgo:
@@ -420,6 +425,7 @@ docker-build-benchnet: docker-build-flow docker-build-loader
420425
docker-push-collection:
421426
docker push "$(CONTAINER_REGISTRY)/collection:$(SHORT_COMMIT)"
422427
docker push "$(CONTAINER_REGISTRY)/collection:$(IMAGE_TAG)"
428+
docker push "$(CONTAINER_REGISTRY)/collection:$(FLOW_GO_TAG)"
423429

424430
.PHONY: docker-push-collection-without-netgo
425431
docker-push-collection-without-netgo:
@@ -433,6 +439,7 @@ docker-push-collection-latest: docker-push-collection
433439
docker-push-consensus:
434440
docker push "$(CONTAINER_REGISTRY)/consensus:$(SHORT_COMMIT)"
435441
docker push "$(CONTAINER_REGISTRY)/consensus:$(IMAGE_TAG)"
442+
docker push "$(CONTAINER_REGISTRY)/consensus:$(FLOW_GO_TAG)"
436443

437444
.PHONY: docker-push-consensus-without-netgo
438445
docker-push-consensus-without-netgo:
@@ -446,6 +453,13 @@ docker-push-consensus-latest: docker-push-consensus
446453
docker-push-execution:
447454
docker push "$(CONTAINER_REGISTRY)/execution:$(SHORT_COMMIT)"
448455
docker push "$(CONTAINER_REGISTRY)/execution:$(IMAGE_TAG)"
456+
docker push "$(CONTAINER_REGISTRY)/execution:$(FLOW_GO_TAG)"
457+
458+
.PHONY: docker-push-execution-corrupt
459+
docker-push-execution-corrupt:
460+
docker push "$(CONTAINER_REGISTRY)/execution-corrupted:$(SHORT_COMMIT)"
461+
docker push "$(CONTAINER_REGISTRY)/execution-corrupted:$(IMAGE_TAG)"
462+
449463

450464
.PHONY: docker-push-execution-without-netgo
451465
docker-push-execution-without-netgo:
@@ -459,6 +473,12 @@ docker-push-execution-latest: docker-push-execution
459473
docker-push-verification:
460474
docker push "$(CONTAINER_REGISTRY)/verification:$(SHORT_COMMIT)"
461475
docker push "$(CONTAINER_REGISTRY)/verification:$(IMAGE_TAG)"
476+
docker push "$(CONTAINER_REGISTRY)/verification:$(FLOW_GO_TAG)"
477+
478+
.PHONY: docker-push-verification-corrupt
479+
docker-push-verification-corrupt:
480+
docker push "$(CONTAINER_REGISTRY)/verification-corrupted:$(SHORT_COMMIT)"
481+
docker push "$(CONTAINER_REGISTRY)/verification-corrupted:$(IMAGE_TAG)"
462482

463483
.PHONY: docker-push-verification-without-netgo
464484
docker-push-verification-without-netgo:
@@ -472,6 +492,12 @@ docker-push-verification-latest: docker-push-verification
472492
docker-push-access:
473493
docker push "$(CONTAINER_REGISTRY)/access:$(SHORT_COMMIT)"
474494
docker push "$(CONTAINER_REGISTRY)/access:$(IMAGE_TAG)"
495+
docker push "$(CONTAINER_REGISTRY)/access:$(FLOW_GO_TAG)"
496+
497+
.PHONY: docker-push-access-corrupt
498+
docker-push-access-corrupt:
499+
docker push "$(CONTAINER_REGISTRY)/access-corrupted:$(SHORT_COMMIT)"
500+
docker push "$(CONTAINER_REGISTRY)/access-corrupted:$(IMAGE_TAG)"
475501

476502
.PHONY: docker-push-access-without-netgo
477503
docker-push-access-without-netgo:
@@ -480,6 +506,7 @@ docker-push-access-without-netgo:
480506
.PHONY: docker-push-access-latest
481507
docker-push-access-latest: docker-push-access
482508
docker push "$(CONTAINER_REGISTRY)/access:latest"
509+
483510

484511
.PHONY: docker-push-observer
485512
docker-push-observer:
@@ -521,6 +548,9 @@ docker-push-flow-without-netgo: docker-push-collection-without-netgo docker-push
521548
.PHONY: docker-push-flow-latest
522549
docker-push-flow-latest: docker-push-collection-latest docker-push-consensus-latest docker-push-execution-latest docker-push-verification-latest docker-push-access-latest docker-push-observer-latest
523550

551+
.PHONY: docker-push-flow-corrupt
552+
docker-push-flow-corrupt: docker-push-access-corrupt docker-push-execution-corrupt docker-push-verification-corrupt
553+
524554
.PHONY: docker-push-benchnet
525555
docker-push-benchnet: docker-push-flow docker-push-loader
526556

@@ -622,4 +652,4 @@ monitor-rollout:
622652
kubectl --kubeconfig=$$kconfig rollout status statefulsets.apps flow-collection-node-v1; \
623653
kubectl --kubeconfig=$$kconfig rollout status statefulsets.apps flow-consensus-node-v1; \
624654
kubectl --kubeconfig=$$kconfig rollout status statefulsets.apps flow-execution-node-v1; \
625-
kubectl --kubeconfig=$$kconfig rollout status statefulsets.apps flow-verification-node-v1
655+
kubectl --kubeconfig=$$kconfig rollout status statefulsets.apps flow-verification-node-v1

cmd/access/node_builder/access_node_builder.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ type FlowAccessNodeBuilder struct {
222222
// engines
223223
IngestEng *ingestion.Engine
224224
RequestEng *requester.Engine
225-
FollowerEng *followereng.Engine
225+
FollowerEng *followereng.ComplianceEngine
226226
SyncEng *synceng.Engine
227227
StateStreamEng *state_stream.Engine
228228
}
@@ -323,7 +323,7 @@ func (builder *FlowAccessNodeBuilder) buildFollowerEngine() *FlowAccessNodeBuild
323323
heroCacheCollector = metrics.FollowerCacheMetrics(node.MetricsRegisterer)
324324
}
325325

326-
core, err := followereng.NewCore(
326+
core, err := followereng.NewComplianceCore(
327327
node.Logger,
328328
node.Metrics.Mempool,
329329
heroCacheCollector,
@@ -338,7 +338,7 @@ func (builder *FlowAccessNodeBuilder) buildFollowerEngine() *FlowAccessNodeBuild
338338
return nil, fmt.Errorf("could not create follower core: %w", err)
339339
}
340340

341-
builder.FollowerEng, err = followereng.New(
341+
builder.FollowerEng, err = followereng.NewComplianceLayer(
342342
node.Logger,
343343
node.Network,
344344
node.Me,

cmd/bootstrap/run/execution_state.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ func GenerateServiceAccountPrivateKey(seed []byte) (flow.AccountPrivateKey, erro
3232
}, nil
3333
}
3434

35-
// NOTE: this is now unused and should become part of another tool.
3635
func GenerateExecutionState(
3736
dbDir string,
3837
accountKey flow.AccountPublicKey,

cmd/collection/main.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ func main() {
8686
ing *ingest.Engine
8787
mainChainSyncCore *chainsync.Core
8888
followerCore *hotstuff.FollowerLoop // follower hotstuff logic
89-
followerEng *followereng.Engine
89+
followerEng *followereng.ComplianceEngine
9090
colMetrics module.CollectionMetrics
9191
err error
9292

@@ -307,7 +307,7 @@ func main() {
307307
heroCacheCollector = metrics.FollowerCacheMetrics(node.MetricsRegisterer)
308308
}
309309

310-
core, err := followereng.NewCore(
310+
core, err := followereng.NewComplianceCore(
311311
node.Logger,
312312
node.Metrics.Mempool,
313313
heroCacheCollector,
@@ -322,7 +322,7 @@ func main() {
322322
return nil, fmt.Errorf("could not create follower core: %w", err)
323323
}
324324

325-
followerEng, err = followereng.New(
325+
followerEng, err = followereng.NewComplianceLayer(
326326
node.Logger,
327327
node.Network,
328328
node.Me,

cmd/consensus/main.go

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -685,20 +685,17 @@ func main() {
685685
return hot, nil
686686
}).
687687
Component("consensus compliance engine", func(node *cmd.NodeConfig) (module.ReadyDoneAware, error) {
688-
// initialize the entity database accessors
689-
cleaner := bstorage.NewCleaner(node.Logger, node.DB, node.Metrics.CleanCollector, flow.DefaultValueLogGCFrequency)
690-
691688
// initialize the pending blocks cache
692689
proposals := buffer.NewPendingBlocks()
693690

694691
logger := createLogger(node.Logger, node.RootChainID)
695-
complianceCore, err := compliance.NewCore(logger,
692+
complianceCore, err := compliance.NewCore(
693+
logger,
696694
node.Metrics.Engine,
697695
node.Metrics.Mempool,
698696
mainMetrics,
699697
node.Metrics.Compliance,
700698
node.Tracer,
701-
cleaner,
702699
node.Storage.Headers,
703700
node.Storage.Payloads,
704701
mutableState,

cmd/execution/README.md

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,6 @@ required to trigger this condition is put in place to prevent triggering it in c
6868
happen on unstable networks.
6969
EN keeps track of the highest block it has executed. This is not a Flow protocol feature, and only serves synchronisation needs.
7070

71-
### Execution State syncing
72-
Other execution node is queried for range of missing blocks and hold authority to decide if it's willing (and able) to answer this query.
73-
If so, it sends the `ExecutionStateDelta` which contains all the block data and results of execution.
74-
Currently, this is fully trusted operation, meaning data is applied as-is without any extra checks.
75-
7671
### Missing blocks
7772
If no other EN are available, the block-level synchronisation is started. This requests blocks from consensus nodes, and
7873
incoming blocks are processed as if they were received during normal mode of operation

cmd/execution_builder.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,8 @@ type ExecutionNode struct {
123123
checkerEng *checker.Engine
124124
syncCore *chainsync.Core
125125
syncEngine *synchronization.Engine
126-
followerCore *hotstuff.FollowerLoop // follower hotstuff logic
127-
followerEng *followereng.Engine // to sync blocks from consensus nodes
126+
followerCore *hotstuff.FollowerLoop // follower hotstuff logic
127+
followerEng *followereng.ComplianceEngine // to sync blocks from consensus nodes
128128
computationManager *computation.Manager
129129
collectionRequester *requester.Engine
130130
ingestionEng *ingestion.Engine
@@ -889,7 +889,7 @@ func (exeNode *ExecutionNode) LoadFollowerEngine(
889889
heroCacheCollector = metrics.FollowerCacheMetrics(node.MetricsRegisterer)
890890
}
891891

892-
core, err := followereng.NewCore(
892+
core, err := followereng.NewComplianceCore(
893893
node.Logger,
894894
node.Metrics.Mempool,
895895
heroCacheCollector,
@@ -904,7 +904,7 @@ func (exeNode *ExecutionNode) LoadFollowerEngine(
904904
return nil, fmt.Errorf("could not create follower core: %w", err)
905905
}
906906

907-
exeNode.followerEng, err = followereng.New(
907+
exeNode.followerEng, err = followereng.NewComplianceLayer(
908908
node.Logger,
909909
node.Network,
910910
node.Me,

cmd/observer/node_builder/observer_builder.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ type ObserverServiceBuilder struct {
183183
SyncEngineParticipantsProviderFactory func() module.IdentifierProvider
184184

185185
// engines
186-
FollowerEng *follower.Engine
186+
FollowerEng *follower.ComplianceEngine
187187
SyncEng *synceng.Engine
188188

189189
// Public network
@@ -354,7 +354,7 @@ func (builder *ObserverServiceBuilder) buildFollowerEngine() *ObserverServiceBui
354354
if node.HeroCacheMetricsEnable {
355355
heroCacheCollector = metrics.FollowerCacheMetrics(node.MetricsRegisterer)
356356
}
357-
core, err := follower.NewCore(
357+
core, err := follower.NewComplianceCore(
358358
node.Logger,
359359
node.Metrics.Mempool,
360360
heroCacheCollector,
@@ -369,7 +369,7 @@ func (builder *ObserverServiceBuilder) buildFollowerEngine() *ObserverServiceBui
369369
return nil, fmt.Errorf("could not create follower core: %w", err)
370370
}
371371

372-
builder.FollowerEng, err = follower.New(
372+
builder.FollowerEng, err = follower.NewComplianceLayer(
373373
node.Logger,
374374
node.Network,
375375
node.Me,

cmd/scaffold.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -887,6 +887,10 @@ func (fnb *FlowNodeBuilder) initDB() error {
887887
return nil
888888
})
889889

890+
fnb.Component("badger log cleaner", func(node *NodeConfig) (module.ReadyDoneAware, error) {
891+
return bstorage.NewCleaner(node.Logger, node.DB, node.Metrics.CleanCollector, flow.DefaultValueLogGCWaitDuration), nil
892+
})
893+
890894
return nil
891895
}
892896

cmd/util/cmd/exec-data-json-export/delta_snapshot_exporter.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import (
88
"path/filepath"
99

1010
"github.com/onflow/flow-go/cmd/util/cmd/common"
11-
"github.com/onflow/flow-go/engine/execution/state/delta"
11+
"github.com/onflow/flow-go/fvm/state"
1212
"github.com/onflow/flow-go/model/flow"
1313
"github.com/onflow/flow-go/module/metrics"
1414
"github.com/onflow/flow-go/storage/badger"
@@ -49,7 +49,7 @@ func ExportDeltaSnapshots(blockID flow.Identifier, dbPath string, outputPath str
4949
return nil
5050
}
5151

52-
var snap []*delta.Snapshot
52+
var snap []*state.ExecutionSnapshot
5353
err = db.View(operation.RetrieveExecutionStateInteractions(activeBlockID, &snap))
5454
if err != nil {
5555
return fmt.Errorf("could not load delta snapshot: %w", err)
@@ -59,13 +59,13 @@ func ExportDeltaSnapshots(blockID flow.Identifier, dbPath string, outputPath str
5959
// end of snapshots
6060
return nil
6161
}
62-
m, err := json.Marshal(snap[0].Delta.UpdatedRegisters())
62+
m, err := json.Marshal(snap[0].UpdatedRegisters())
6363
if err != nil {
6464
return fmt.Errorf("could not load delta snapshot: %w", err)
6565
}
6666

6767
reads := make([]string, 0)
68-
for _, r := range snap[0].Reads {
68+
for _, r := range snap[0].ReadSet {
6969

7070
json, err := json.Marshal(r)
7171
if err != nil {

0 commit comments

Comments
 (0)