Skip to content

Commit

Permalink
Merge branch 'develop' into sync2/rangesync-recent
Browse files Browse the repository at this point in the history
  • Loading branch information
ivan4th committed Oct 28, 2024
2 parents 93d76ca + 517c305 commit 8ca810a
Show file tree
Hide file tree
Showing 145 changed files with 1,737 additions and 1,482 deletions.
12 changes: 6 additions & 6 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# go-spacemesh needs at least ubuntu 22.04. newer versions of ubuntu might work as well, but are untested
FROM ubuntu:22.04 AS linux
ENV DEBIAN_FRONTEND noninteractive
ENV SHELL /bin/bash
ENV DEBIAN_FRONTEND=noninteractive
ENV SHELL=/bin/bash
ARG TZ=Etc/UTC
ENV TZ=${TZ}
USER root
Expand All @@ -22,11 +22,11 @@ RUN set -ex \
&& locale-gen en_US.UTF-8 \
&& update-locale LANG=en_US.UTF-8 \
&& echo "$TZ" > /etc/timezone
ENV LANG en_US.UTF-8
ENV LANGUAGE en_US.UTF-8
ENV LC_ALL en_US.UTF-8
ENV LANG=en_US.UTF-8
ENV LANGUAGE=en_US.UTF-8
ENV LC_ALL=en_US.UTF-8

FROM golang:1.23 as builder
FROM golang:1.23 AS builder
ARG VERSION=""
ENV VERSION=${VERSION}
RUN set -ex \
Expand Down
12 changes: 8 additions & 4 deletions activation/activation.go
Original file line number Diff line number Diff line change
Expand Up @@ -586,12 +586,10 @@ func (b *Builder) BuildNIPostChallenge(ctx context.Context, nodeID types.NodeID)
switch {
case errors.Is(err, sql.ErrNotFound):
logger.Info("no previous ATX found, creating an initial nipost challenge")

challenge, err = b.buildInitialNIPostChallenge(ctx, logger, nodeID, publishEpochId)
if err != nil {
return nil, err
}

case err != nil:
return nil, fmt.Errorf("get last ATX: %w", err)
default:
Expand Down Expand Up @@ -662,7 +660,8 @@ func (b *Builder) buildInitialNIPostChallenge(
) (*types.NIPostChallenge, error) {
post, err := nipost.GetPost(b.localDB, nodeID)
if err != nil {
return nil, fmt.Errorf("get initial post: %w", err)
// if initial post is not found, declare it invalid so it is regenerated
return nil, ErrInvalidInitialPost
}
logger.Info("verifying the initial post")
initialPost := &types.Post{
Expand All @@ -671,7 +670,12 @@ func (b *Builder) buildInitialNIPostChallenge(
Pow: post.Pow,
}
err = b.validator.PostV2(ctx, nodeID, post.CommitmentATX, initialPost, shared.ZeroChallenge, post.NumUnits)
if err != nil {
switch {
case errors.Is(err, context.Canceled):
return nil, err
case errors.Is(err, context.DeadlineExceeded):
return nil, err
case err != nil:
logger.Error("initial POST is invalid", zap.Error(err))
if err := nipost.RemovePost(b.localDB, nodeID); err != nil {
logger.Fatal("failed to remove initial post", zap.Error(err))
Expand Down
64 changes: 62 additions & 2 deletions activation/activation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ func newTestBuilder(tb testing.TB, numSigners int, opts ...BuilderOption) *testA

ctrl := gomock.NewController(tb)
tab := &testAtxBuilder{
db: statesql.InMemory(),
localDb: localsql.InMemory(sql.WithConnections(numSigners)),
db: statesql.InMemoryTest(tb),
localDb: localsql.InMemoryTest(tb, sql.WithConnections(numSigners)),
goldenATXID: types.ATXID(types.HexToHash32("77777")),

observedLogs: observedLogs,
Expand Down Expand Up @@ -705,6 +705,66 @@ func TestBuilder_PublishActivationTx_NoPrevATX(t *testing.T) {
require.ErrorIs(t, err, sql.ErrNotFound)
}

func TestBuilder_PublishActivationTx_NoPrevATX_ValidatingInitialPostTimeout(t *testing.T) {
tab := newTestBuilder(t, 1, WithPoetConfig(PoetConfig{PhaseShift: layerDuration * 4}))
sig := maps.Values(tab.signers)[0]

posEpoch := postGenesisEpoch
currLayer := posEpoch.FirstLayer()

// generate and store initial post in state
post := nipost.Post{
Indices: types.RandomBytes(10),
Nonce: rand.Uint32(),
Pow: rand.Uint64(),

NumUnits: uint32(12),
CommitmentATX: types.RandomATXID(),
VRFNonce: types.VRFPostIndex(rand.Uint64()),
Challenge: shared.ZeroChallenge,
}
require.NoError(t, nipost.AddPost(tab.localDb, sig.NodeID(), post))
initialPost := &types.Post{
Nonce: post.Nonce,
Indices: post.Indices,
Pow: post.Pow,
}
tab.mValidator.EXPECT().
PostV2(gomock.Any(), sig.NodeID(), post.CommitmentATX, initialPost, shared.ZeroChallenge, post.NumUnits).
Return(context.DeadlineExceeded)

// create and publish ATX
tab.mclock.EXPECT().CurrentLayer().Return(currLayer).AnyTimes()
tab.mclock.EXPECT().LayerToTime(gomock.Any()).DoAndReturn(func(got types.LayerID) time.Time {
genesis := time.Now().Add(-time.Duration(currLayer) * layerDuration)
return genesis.Add(layerDuration * time.Duration(got))
}).AnyTimes()
err := tab.PublishActivationTx(context.Background(), tab.signers[sig.NodeID()])
require.ErrorIs(t, err, context.DeadlineExceeded)

// initial post is preserved
got, err := nipost.GetPost(tab.localDB, sig.NodeID())
require.NoError(t, err)
require.Equal(t, post, *got)
}

func TestBuilder_PublishActivationTx_NoPrevATX_MissingInitialPost(t *testing.T) {
tab := newTestBuilder(t, 1, WithPoetConfig(PoetConfig{PhaseShift: layerDuration * 4}))
sig := maps.Values(tab.signers)[0]

posEpoch := postGenesisEpoch
currLayer := posEpoch.FirstLayer()

// no initial post in state
tab.mclock.EXPECT().CurrentLayer().Return(currLayer).AnyTimes()
tab.mclock.EXPECT().LayerToTime(gomock.Any()).DoAndReturn(func(got types.LayerID) time.Time {
genesis := time.Now().Add(-time.Duration(currLayer) * layerDuration)
return genesis.Add(layerDuration * time.Duration(got))
}).AnyTimes()
err := tab.PublishActivationTx(context.Background(), tab.signers[sig.NodeID()])
require.ErrorIs(t, err, ErrInvalidInitialPost)
}

func TestBuilder_PublishActivationTx_NoPrevATX_PublishFails_InitialPost_preserved(t *testing.T) {
tab := newTestBuilder(t, 1, WithPoetConfig(PoetConfig{PhaseShift: layerDuration * 4}))
sig := maps.Values(tab.signers)[0]
Expand Down
16 changes: 8 additions & 8 deletions activation/certifier_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import (
func TestPersistsCerts(t *testing.T) {
client := NewMockcertifierClient(gomock.NewController(t))
id := types.RandomNodeID()
db := localsql.InMemory()
db := localsql.InMemoryTest(t)
cert := &certdb.PoetCert{Data: []byte("cert"), Signature: []byte("sig")}
certifierAddress := &url.URL{Scheme: "http", Host: "certifier.org"}
pubkey := []byte("pubkey")
Expand Down Expand Up @@ -56,7 +56,7 @@ func TestPersistsCerts(t *testing.T) {
}

func TestAvoidsRedundantQueries(t *testing.T) {
db := localsql.InMemory()
db := localsql.InMemoryTest(t)
client := NewMockcertifierClient(gomock.NewController(t))
id1 := types.RandomNodeID()
id2 := types.RandomNodeID()
Expand Down Expand Up @@ -114,16 +114,16 @@ func TestObtainingPost(t *testing.T) {
id := types.RandomNodeID()

t.Run("no POST or ATX", func(t *testing.T) {
db := statesql.InMemory()
localDb := localsql.InMemory()
db := statesql.InMemoryTest(t)
localDb := localsql.InMemoryTest(t)

certifier := NewCertifierClient(db, localDb, zaptest.NewLogger(t))
_, err := certifier.obtainPost(context.Background(), id)
require.ErrorContains(t, err, "PoST not found")
})
t.Run("initial POST available", func(t *testing.T) {
db := statesql.InMemory()
localDb := localsql.InMemory()
db := statesql.InMemoryTest(t)
localDb := localsql.InMemoryTest(t)

post := nipost.Post{
Nonce: 30,
Expand All @@ -143,8 +143,8 @@ func TestObtainingPost(t *testing.T) {
require.Equal(t, post, *got)
})
t.Run("initial POST unavailable but ATX exists", func(t *testing.T) {
db := statesql.InMemory()
localDb := localsql.InMemory()
db := statesql.InMemoryTest(t)
localDb := localsql.InMemoryTest(t)

atx := newInitialATXv1(t, types.RandomATXID())
atx.SmesherID = id
Expand Down
8 changes: 4 additions & 4 deletions activation/e2e/activation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ import (
"github.com/spacemeshos/go-spacemesh/timesync"
)

func syncedSyncer(t testing.TB) *activation.Mocksyncer {
syncer := activation.NewMocksyncer(gomock.NewController(t))
func syncedSyncer(tb testing.TB) *activation.Mocksyncer {
syncer := activation.NewMocksyncer(gomock.NewController(tb))
syncer.EXPECT().RegisterForATXSynced().DoAndReturn(func() <-chan struct{} {
synced := make(chan struct{})
close(synced)
Expand All @@ -61,8 +61,8 @@ func Test_BuilderWithMultipleClients(t *testing.T) {
logger := zaptest.NewLogger(t)
goldenATX := types.ATXID{2, 3, 4}
cfg := testPostConfig()
db := statesql.InMemory()
localDB := localsql.InMemory()
db := statesql.InMemoryTest(t)
localDB := localsql.InMemoryTest(t)

svc := grpcserver.NewPostService(logger, grpcserver.PostServiceQueryInterval(100*time.Millisecond))
svc.AllowConnections(true)
Expand Down
21 changes: 11 additions & 10 deletions activation/e2e/atx_merge_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,16 @@ const (
testTickSize = 1
)

func constructMerkleProof(t testing.TB, members []types.Hash32, ids map[uint64]bool) wire.MerkleProofV2 {
t.Helper()
func constructMerkleProof(tb testing.TB, members []types.Hash32, ids map[uint64]bool) wire.MerkleProofV2 {
tb.Helper()

tree, err := merkle.NewTreeBuilder().
WithLeavesToProve(ids).
WithHashFunc(shared.HashMembershipTreeNode).
Build()
require.NoError(t, err)
require.NoError(tb, err)
for _, member := range members {
require.NoError(t, tree.AddLeaf(member[:]))
require.NoError(tb, tree.AddLeaf(member[:]))
}
nodes := tree.Proof()
nodesH32 := make([]types.Hash32, 0, len(nodes))
Expand Down Expand Up @@ -140,7 +140,7 @@ func createSoloAtx(publish types.EpochID, prev, pos types.ATXID, nipost *nipost.
}

func createMerged(
t testing.TB,
tb testing.TB,
niposts []nipostData,
publish types.EpochID,
marriage, positioning types.ATXID,
Expand All @@ -162,7 +162,7 @@ func createMerged(
// Append PoSTs for all IDs
for i, nipost := range niposts {
idx := slices.IndexFunc(previous, func(a types.ATXID) bool { return a == nipost.previous })
require.NotEqual(t, -1, idx)
require.NotEqual(tb, -1, idx)
atx.NiPosts[0].Posts = append(atx.NiPosts[0].Posts, wire.SubPostV2{
MarriageIndex: uint32(i),
PrevATXIndex: uint32(idx),
Expand All @@ -174,16 +174,16 @@ func createMerged(
return atx
}

func signers(t testing.TB, keysHex []string) []*signing.EdSigner {
t.Helper()
func signers(tb testing.TB, keysHex []string) []*signing.EdSigner {
tb.Helper()

signers := make([]*signing.EdSigner, 0, len(keysHex))
for _, k := range keysHex {
key, err := hex.DecodeString(k)
require.NoError(t, err)
require.NoError(tb, err)

sig, err := signing.NewEdSigner(signing.WithPrivateKey(key))
require.NoError(t, err)
require.NoError(tb, err)
signers = append(signers, sig)
}
return signers
Expand Down Expand Up @@ -211,6 +211,7 @@ func Test_MarryAndMerge(t *testing.T) {
cfg := testPostConfig()
db := statesql.InMemoryTest(t)
cdb := datastore.NewCachedDB(db, logger)
t.Cleanup(func() { assert.NoError(t, cdb.Close()) })
localDB := localsql.InMemoryTest(t)

svc := grpcserver.NewPostService(logger, grpcserver.PostServiceQueryInterval(100*time.Millisecond))
Expand Down
5 changes: 3 additions & 2 deletions activation/e2e/builds_atx_v2_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,9 @@ func TestBuilder_SwitchesToBuildV2(t *testing.T) {
require.NoError(t, err)

cfg := testPostConfig()
db := statesql.InMemory()
db := statesql.InMemoryTest(t)
cdb := datastore.NewCachedDB(db, logger)
t.Cleanup(func() { assert.NoError(t, cdb.Close()) })

opts := testPostSetupOpts(t)
svc := grpcserver.NewPostService(logger, grpcserver.PostServiceQueryInterval(100*time.Millisecond))
Expand Down Expand Up @@ -96,7 +97,7 @@ func TestBuilder_SwitchesToBuildV2(t *testing.T) {
client := ae2e.NewTestPoetClient(1, poetCfg)
poetClient := activation.NewPoetServiceWithClient(poetDb, client, poetCfg, logger, testTickSize)

localDB := localsql.InMemory()
localDB := localsql.InMemoryTest(t)
nb, err := activation.NewNIPostBuilder(
localDB,
svc,
Expand Down
22 changes: 11 additions & 11 deletions activation/e2e/certifier_client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ func TestCertification(t *testing.T) {
require.NoError(t, err)

cfg := testPostConfig()
db := statesql.InMemory()
localDb := localsql.InMemory()
db := statesql.InMemoryTest(t)
localDb := localsql.InMemoryTest(t)

opts := testPostSetupOpts(t)
logger := zaptest.NewLogger(t)
Expand Down Expand Up @@ -171,26 +171,26 @@ func (c *testCertifier) certify(w http.ResponseWriter, r *http.Request) {
}

func spawnTestCertifier(
t *testing.T,
tb testing.TB,
cfg activation.PostConfig,
// optional - if nil, will create valid certs
makeCert func(nodeID []byte) *poetShared.Cert,
opts ...verifying.OptionFunc,
) (ed25519.PublicKey, net.Addr) {
t.Helper()
tb.Helper()

pub, private, err := ed25519.GenerateKey(nil)
require.NoError(t, err)
require.NoError(tb, err)

postVerifier, err := activation.NewPostVerifier(
cfg,
zaptest.NewLogger(t),
zaptest.NewLogger(tb),
activation.WithVerifyingOpts(activation.DefaultTestPostVerifyingOpts()),
)
require.NoError(t, err)
require.NoError(tb, err)
var eg errgroup.Group
l, err := net.Listen("tcp", ":0")
require.NoError(t, err)
require.NoError(tb, err)
eg.Go(func() error {
certifier := &testCertifier{
privKey: private,
Expand All @@ -205,9 +205,9 @@ func spawnTestCertifier(
http.Serve(l, mux)
return nil
})
t.Cleanup(func() {
require.NoError(t, l.Close())
require.NoError(t, eg.Wait())
tb.Cleanup(func() {
require.NoError(tb, l.Close())
require.NoError(tb, eg.Wait())
})

return pub, l.Addr()
Expand Down
6 changes: 4 additions & 2 deletions activation/e2e/checkpoint_merged_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ func Test_CheckpointAfterMerge(t *testing.T) {
cfg := testPostConfig()
db := statesql.InMemoryTest(t)
cdb := datastore.NewCachedDB(db, logger)
t.Cleanup(func() { assert.NoError(t, cdb.Close()) })
localDB := localsql.InMemoryTest(t)

svc := grpcserver.NewPostService(logger, grpcserver.PostServiceQueryInterval(100*time.Millisecond))
Expand Down Expand Up @@ -283,14 +284,15 @@ func Test_CheckpointAfterMerge(t *testing.T) {
// 4. Spawn new ATX handler and builder using the new DB
poetDb, err = activation.NewPoetDb(newDB, logger.Named("poetDb"))
require.NoError(t, err)
cdb = datastore.NewCachedDB(newDB, logger)
newCdb := datastore.NewCachedDB(newDB, logger)
t.Cleanup(func() { assert.NoError(t, newCdb.Close()) })

poetSvc = activation.NewPoetServiceWithClient(poetDb, client, poetCfg, logger, testTickSize)
validator = activation.NewValidator(newDB, poetDb, cfg, opts.Scrypt, verifier)
require.NoError(t, err)
atxHdlr = activation.NewHandler(
"local",
cdb,
newCdb,
atxsdata.New(),
signing.NewEdVerifier(),
clock,
Expand Down
Loading

0 comments on commit 8ca810a

Please sign in to comment.