Skip to content

Commit

Permalink
Flag disable post verification (#5517)
Browse files Browse the repository at this point in the history
There are setups with one _public_ node that "talks to the Internet" and stands in front of more _private_ nodes that only connect to that _public_ node. In such a setup, the private nodes can trust that the public one already verified all data coming from the network and it is not required to repeat that work. The PoST proofs of ATXs are especially heavy.
  • Loading branch information
poszu committed Jan 31, 2024
1 parent 2280341 commit c307288
Show file tree
Hide file tree
Showing 10 changed files with 127 additions and 63 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ See [RELEASE](./RELEASE.md) for workflow instructions.

## Release v1.3.8

### Features

* [#5517](https://github.com/spacemeshos/go-spacemesh/pull/5517)
Added a flag `--smeshing-opts-verifying-disable` and a config parameter `smeshing-opts-verifying-disable`
meant for disabling verifying POST in incoming ATXs on private nodes.
The verification should be performed by the public node instead.

### Improvements

* [#5441](https://github.com/spacemeshos/go-spacemesh/pull/5441)
Expand Down
3 changes: 0 additions & 3 deletions activation/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ type Handler struct {
log log.Log
mu sync.Mutex
fetcher system.Fetcher
poetCfg PoetConfig

signerMtx sync.Mutex
signers map[types.NodeID]*signing.EdSigner
Expand All @@ -75,7 +74,6 @@ func NewHandler(
beacon AtxReceiver,
tortoise system.Tortoise,
log log.Log,
poetCfg PoetConfig,
) *Handler {
return &Handler{
local: local,
Expand All @@ -91,7 +89,6 @@ func NewHandler(
fetcher: fetcher,
beacon: beacon,
tortoise: tortoise,
poetCfg: poetCfg,

signers: make(map[types.NodeID]*signing.EdSigner),
inProgress: make(map[types.ATXID][]chan error),
Expand Down
1 change: 0 additions & 1 deletion activation/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,6 @@ func newTestHandler(tb testing.TB, goldenATXID types.ATXID) *testHandler {
mbeacon,
mtortoise,
lg,
PoetConfig{},
)
return &testHandler{
Handler: atxHdlr,
Expand Down
5 changes: 5 additions & 0 deletions activation/post.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ func DefaultPostProvingOpts() PostProvingOpts {

// PostProofVerifyingOpts are the options controlling POST proving process.
type PostProofVerifyingOpts struct {
// Disable verifying POST proofs. Experimental.
// Use with caution, only on private nodes with a trusted public peer that
// validates the proofs.
Disabled bool `mapstructure:"smeshing-opts-verifying-disable"`

// Number of workers spawned to verify proofs.
Workers int `mapstructure:"smeshing-opts-verifying-workers"`
// The minimum number of verifying workers to keep
Expand Down
103 changes: 78 additions & 25 deletions activation/post_verifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func (a autoscaler) run(stop chan struct{}, s scaler, min, target int) {
}
}

type OffloadingPostVerifier struct {
type offloadingPostVerifier struct {
eg errgroup.Group
log *zap.Logger
verifier PostVerifier
Expand Down Expand Up @@ -97,40 +97,79 @@ func (v *postVerifier) Verify(
return v.ProofVerifier.Verify(p, m, v.cfg, v.logger, opts...)
}

// NewPostVerifier creates a new post verifier.
func NewPostVerifier(cfg PostConfig, logger *zap.Logger, opts ...verifying.OptionFunc) (PostVerifier, error) {
verifier, err := verifying.NewProofVerifier(opts...)
if err != nil {
return nil, err
type postVerifierOpts struct {
opts PostProofVerifyingOpts
prioritizedIds []types.NodeID
autoscaling bool
}

type PostVerifierOpt func(v *postVerifierOpts)

func WithVerifyingOpts(opts PostProofVerifyingOpts) PostVerifierOpt {
return func(v *postVerifierOpts) {
v.opts = opts
}
}

return &postVerifier{logger: logger, ProofVerifier: verifier, cfg: cfg.ToConfig()}, nil
func PrioritizedIDs(ids ...types.NodeID) PostVerifierOpt {
return func(v *postVerifierOpts) {
v.prioritizedIds = ids
}
}

type OffloadingPostVerifierOpt func(v *OffloadingPostVerifier)
func WithAutoscaling() PostVerifierOpt {
return func(v *postVerifierOpts) {
v.autoscaling = true
}
}

func PrioritizedIDs(ids ...types.NodeID) OffloadingPostVerifierOpt {
return func(v *OffloadingPostVerifier) {
for _, id := range ids {
v.prioritizedIds[id] = struct{}{}
}
// NewPostVerifier creates a new post verifier.
func NewPostVerifier(cfg PostConfig, logger *zap.Logger, opts ...PostVerifierOpt) (PostVerifier, error) {
options := &postVerifierOpts{
opts: DefaultPostVerifyingOpts(),
}
for _, o := range opts {
o(options)
}
if options.opts.Disabled {
logger.Warn("verifying post proofs is disabled")
return &noopPostVerifier{}, nil
}

logger.Debug("creating post verifier")
verifier, err := verifying.NewProofVerifier(verifying.WithPowFlags(options.opts.Flags.Value()))
logger.Debug("created post verifier", zap.Error(err))
if err != nil {
return nil, err
}

Check warning on line 144 in activation/post_verifier.go

View check run for this annotation

Codecov / codecov/patch

activation/post_verifier.go#L143-L144

Added lines #L143 - L144 were not covered by tests
workers := options.opts.Workers
minWorkers := min(options.opts.MinWorkers, workers)
offloadingVerifier := newOffloadingPostVerifier(
&postVerifier{logger: logger, ProofVerifier: verifier, cfg: cfg.ToConfig()},
workers,
logger,
options.prioritizedIds...,
)
if options.autoscaling && minWorkers != workers {
offloadingVerifier.autoscale(minWorkers, workers)
}
return offloadingVerifier, nil
}

// NewOffloadingPostVerifier creates a new post proof verifier with the given number of workers.
// newOffloadingPostVerifier creates a new post proof verifier with the given number of workers.
// The verifier will distribute incoming proofs between the workers.
// It will block if all workers are busy.
//
// SAFETY: The `verifier` must be safe to use concurrently.
//
// The verifier must be closed after use with Close().
func NewOffloadingPostVerifier(
func newOffloadingPostVerifier(
verifier PostVerifier,
numWorkers int,
logger *zap.Logger,
opts ...OffloadingPostVerifierOpt,
) *OffloadingPostVerifier {
v := &OffloadingPostVerifier{
prioritizedIds ...types.NodeID,
) *offloadingPostVerifier {
v := &offloadingPostVerifier{
log: logger,
workers: make([]*postVerifierWorker, 0, numWorkers),
prioritized: make(chan *verifyPostJob, numWorkers),
Expand All @@ -139,9 +178,8 @@ func NewOffloadingPostVerifier(
verifier: verifier,
prioritizedIds: make(map[types.NodeID]struct{}),
}

for _, o := range opts {
o(v)
for _, id := range prioritizedIds {
v.prioritizedIds[id] = struct{}{}
}

v.log.Info("starting post verifier")
Expand All @@ -152,7 +190,7 @@ func NewOffloadingPostVerifier(

// Turn on automatic scaling of the number of workers.
// The number of workers will be scaled between `min` and `target` (inclusive).
func (v *OffloadingPostVerifier) Autoscale(min, target int) {
func (v *offloadingPostVerifier) autoscale(min, target int) {
a, err := newAutoscaler()
if err != nil {
v.log.Panic("failed to create autoscaler", zap.Error(err))
Expand All @@ -165,7 +203,7 @@ func (v *OffloadingPostVerifier) Autoscale(min, target int) {
// SAFETY: Must not be called concurrently.
// This is satisfied by the fact that the only caller is the autoscaler,
// which executes scale() serially.
func (v *OffloadingPostVerifier) scale(target int) {
func (v *offloadingPostVerifier) scale(target int) {
v.log.Info("scaling post verifier", zap.Int("current", len(v.workers)), zap.Int("new", target))

if target > len(v.workers) {
Expand All @@ -192,7 +230,7 @@ func (v *OffloadingPostVerifier) scale(target int) {
}
}

func (v *OffloadingPostVerifier) Verify(
func (v *offloadingPostVerifier) Verify(
ctx context.Context,
p *shared.Proof,
m *shared.ProofMetadata,
Expand Down Expand Up @@ -237,7 +275,7 @@ func (v *OffloadingPostVerifier) Verify(
}
}

func (v *OffloadingPostVerifier) Close() error {
func (v *offloadingPostVerifier) Close() error {
select {
case <-v.stop:
return nil
Expand Down Expand Up @@ -275,3 +313,18 @@ func (w *postVerifierWorker) start() {
}
}
}

type noopPostVerifier struct{}

func (v *noopPostVerifier) Verify(
_ context.Context,
_ *shared.Proof,
_ *shared.ProofMetadata,
_ ...verifying.OptionFunc,
) error {
return nil
}

func (v *noopPostVerifier) Close() error {
return nil
}
2 changes: 1 addition & 1 deletion activation/post_verifier_scaling_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func TestAutoScaling(t *testing.T) {
func TestPostVerifierScaling(t *testing.T) {
// 0 workers - no one will verify the proof
mockVerifier := NewMockPostVerifier(gomock.NewController(t))
v := NewOffloadingPostVerifier(mockVerifier, 0, zaptest.NewLogger(t))
v := newOffloadingPostVerifier(mockVerifier, 0, zaptest.NewLogger(t))

ctx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond)
defer cancel()
Expand Down
35 changes: 22 additions & 13 deletions activation/post_verifier_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package activation_test
package activation

import (
"context"
Expand All @@ -9,19 +9,19 @@ import (
"github.com/spacemeshos/post/shared"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
"go.uber.org/zap"
"go.uber.org/zap/zaptest"
"golang.org/x/sync/errgroup"

"github.com/spacemeshos/go-spacemesh/activation"
"github.com/spacemeshos/go-spacemesh/common/types"
)

func TestOffloadingPostVerifier(t *testing.T) {
proof := shared.Proof{}
metadata := shared.ProofMetadata{}

verifier := activation.NewMockPostVerifier(gomock.NewController(t))
offloadingVerifier := activation.NewOffloadingPostVerifier(verifier, 1, zaptest.NewLogger(t))
verifier := NewMockPostVerifier(gomock.NewController(t))
offloadingVerifier := newOffloadingPostVerifier(verifier, 1, zaptest.NewLogger(t))
defer offloadingVerifier.Close()
verifier.EXPECT().Close().Return(nil)

Expand All @@ -35,7 +35,7 @@ func TestOffloadingPostVerifier(t *testing.T) {
}

func TestPostVerifierDetectsInvalidProof(t *testing.T) {
verifier, err := activation.NewPostVerifier(activation.PostConfig{}, zaptest.NewLogger(t))
verifier, err := NewPostVerifier(PostConfig{}, zaptest.NewLogger(t))
require.NoError(t, err)
defer verifier.Close()
require.Error(t, verifier.Verify(context.Background(), &shared.Proof{}, &shared.ProofMetadata{}))
Expand All @@ -45,8 +45,8 @@ func TestPostVerifierVerifyAfterStop(t *testing.T) {
proof := shared.Proof{}
metadata := shared.ProofMetadata{}

verifier := activation.NewMockPostVerifier(gomock.NewController(t))
offloadingVerifier := activation.NewOffloadingPostVerifier(verifier, 1, zaptest.NewLogger(t))
verifier := NewMockPostVerifier(gomock.NewController(t))
offloadingVerifier := newOffloadingPostVerifier(verifier, 1, zaptest.NewLogger(t))
defer offloadingVerifier.Close()

verifier.EXPECT().Verify(gomock.Any(), &proof, &metadata, gomock.Any()).Return(nil)
Expand All @@ -65,8 +65,8 @@ func TestPostVerifierNoRaceOnClose(t *testing.T) {
var proof shared.Proof
var metadata shared.ProofMetadata

verifier := activation.NewMockPostVerifier(gomock.NewController(t))
offloadingVerifier := activation.NewOffloadingPostVerifier(verifier, 1, zaptest.NewLogger(t))
verifier := NewMockPostVerifier(gomock.NewController(t))
offloadingVerifier := newOffloadingPostVerifier(verifier, 1, zaptest.NewLogger(t))
defer offloadingVerifier.Close()

verifier.EXPECT().Close().AnyTimes().Return(nil)
Expand All @@ -91,9 +91,9 @@ func TestPostVerifierNoRaceOnClose(t *testing.T) {
}

func TestPostVerifierClose(t *testing.T) {
verifier := activation.NewMockPostVerifier(gomock.NewController(t))
verifier := NewMockPostVerifier(gomock.NewController(t))
// 0 workers - no one will verify the proof
v := activation.NewOffloadingPostVerifier(verifier, 0, zaptest.NewLogger(t))
v := newOffloadingPostVerifier(verifier, 0, zaptest.NewLogger(t))

verifier.EXPECT().Close().Return(nil)
require.NoError(t, v.Close())
Expand All @@ -104,8 +104,8 @@ func TestPostVerifierClose(t *testing.T) {

func TestPostVerifierPrioritization(t *testing.T) {
nodeID := types.RandomNodeID()
verifier := activation.NewMockPostVerifier(gomock.NewController(t))
v := activation.NewOffloadingPostVerifier(verifier, 2, zaptest.NewLogger(t), activation.PrioritizedIDs(nodeID))
verifier := NewMockPostVerifier(gomock.NewController(t))
v := newOffloadingPostVerifier(verifier, 2, zaptest.NewLogger(t), nodeID)

verifier.EXPECT().
Verify(gomock.Any(), gomock.Any(), &shared.ProofMetadata{NodeId: nodeID.Bytes()}, gomock.Any()).
Expand All @@ -114,3 +114,12 @@ func TestPostVerifierPrioritization(t *testing.T) {
err := v.Verify(context.Background(), &shared.Proof{}, &shared.ProofMetadata{NodeId: nodeID.Bytes()})
require.NoError(t, err)
}

func TestVerificationDisabled(t *testing.T) {
opts := DefaultPostVerifyingOpts()
opts.Disabled = true
v, err := NewPostVerifier(DefaultPostConfig(), zap.NewNop(), WithVerifyingOpts(opts))
require.NoError(t, err)
require.NoError(t, v.Verify(context.Background(), &shared.Proof{}, &shared.ProofMetadata{}))
require.NoError(t, v.Close())
}
1 change: 0 additions & 1 deletion checkpoint/recovery_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,6 @@ func validateAndPreserveData(
mreceiver,
mtrtl,
lg,
activation.PoetConfig{},
)
mfetch.EXPECT().GetAtxs(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
for i, vatx := range deps {
Expand Down
7 changes: 7 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,13 @@ func AddCommands(cmd *cobra.Command) {

/**======================== PoST Verifying Flags ========================== **/

cmd.PersistentFlags().BoolVar(
&cfg.SMESHING.VerifyingOpts.Disabled,
"smeshing-opts-verifying-disable",
false,
"Disable verifying POST proofs. Experimental.\n"+
"Use with caution, only on private nodes with a trusted public peer that validates the proofs.",
)
cmd.PersistentFlags().IntVar(
&cfg.SMESHING.VerifyingOpts.MinWorkers,
"smeshing-opts-verifying-min-workers",
Expand Down
Loading

0 comments on commit c307288

Please sign in to comment.