Skip to content

Commit

Permalink
Initial certification using existing ATX or initial POST
Browse files Browse the repository at this point in the history
  • Loading branch information
poszu committed Nov 6, 2023
1 parent 2540b1e commit 40a4697
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 13 deletions.
62 changes: 59 additions & 3 deletions activation/activation.go
Original file line number Diff line number Diff line change
Expand Up @@ -316,15 +316,69 @@ func (b *Builder) generateInitialPost(ctx context.Context) error {
return nil
}

// Obtain certificates for the poets.
// We want to certify immediately after the startup or creating the initial POST
// to avoid all nodes spamming the certifier at the same time when
// submitting to the poets.
//
// New nodes should call it after the initial POST is created.
func (b *Builder) certifyPost(ctx context.Context) {
post, meta, err := b.obtainPostForCertification()
if err != nil {
b.log.With().Error("failed to obtain post for certification", log.Err(err))
}

client := NewCertifierClient(b.log.Zap(), post, meta)
b.certifier = NewCertifier(b.nipostBuilder.DataDir(), b.log.Zap(), client)
b.certifier.CertifyAll(ctx, b.poets)
}

func (b *Builder) obtainPostForCertification() (*types.Post, *types.PostInfo, error) {
var (
post *types.Post
meta *types.PostInfo
)

if b.initialPost != nil {
b.log.Info("certifying using the initial post")
return b.initialPost, b.initialPostInfo, nil
}

b.log.Info("certifying using an existing ATX")
atxid, err := atxs.GetFirstIDByNodeID(b.cdb, b.SmesherID())
if err != nil {
return nil, nil, fmt.Errorf("cannot certify - no existing ATX found: %w", err)
}
atx, err := b.cdb.GetFullAtx(atxid)
if err != nil {
return nil, nil, fmt.Errorf("cannot certify - failed to retrieve ATX: %w", err)
}

Check warning on line 355 in activation/activation.go

View check run for this annotation

Codecov / codecov/patch

activation/activation.go#L354-L355

Added lines #L354 - L355 were not covered by tests
var commitmentAtx *types.ATXID
if commitmentAtx = atx.CommitmentATX; commitmentAtx == nil {
atx, err := atxs.CommitmentATX(b.cdb, b.SmesherID())
if err != nil {
return nil, nil, fmt.Errorf("cannot determine own commitment ATX: %w", err)
}
commitmentAtx = &atx

Check warning on line 362 in activation/activation.go

View check run for this annotation

Codecov / codecov/patch

activation/activation.go#L362

Added line #L362 was not covered by tests
}
post = atx.NIPost.Post
meta = &types.PostInfo{
NodeID: b.SmesherID(),
CommitmentATX: *commitmentAtx,
Nonce: atx.VRFNonce,
NumUnits: atx.NumUnits,
LabelsPerUnit: atx.NIPost.PostMetadata.LabelsPerUnit,
}

return post, meta, nil
}

func (b *Builder) run(ctx context.Context) {
defer b.log.Info("atx builder stopped")

for {
err := b.generateInitialPost(ctx)
if err == nil {
client := NewCertifierClient(b.log.Zap(), b.initialPost, b.initialPostInfo)
b.certifier = NewCertifier(b.nipostBuilder.DataDir(), b.log.Zap(), client)
b.certifier.CertifyAll(ctx, b.poets)
break
}
b.log.Error("Failed to generate initial proof: %s", err)
Expand All @@ -336,6 +390,8 @@ func (b *Builder) run(ctx context.Context) {
}
}

b.certifyPost(ctx)

for {
ctx := log.WithNewSessionID(ctx)
err := b.PublishActivationTx(ctx)
Expand Down
56 changes: 52 additions & 4 deletions activation/activation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,10 +160,6 @@ func newTestBuilder(tb testing.TB, opts ...BuilderOption) *testAtxBuilder {
tab.msync,
lg,
opts...)
b.initialPost = &types.Post{
Nonce: 0,
Indices: make([]byte, 10),
}
tab.Builder = b
dir := tb.TempDir()
tab.mnipost.EXPECT().DataDir().Return(dir).AnyTimes()
Expand Down Expand Up @@ -865,6 +861,8 @@ func TestBuilder_PublishActivationTx_TargetsEpochBasedOnPosAtx(t *testing.T) {
return nil
})

tab.mpostClient.EXPECT().Proof(gomock.Any(), shared.ZeroChallenge).Return(&types.Post{}, &types.PostInfo{}, nil)
r.NoError(tab.generateInitialPost(context.Background()))
r.NoError(tab.PublishActivationTx(context.Background()))
}

Expand Down Expand Up @@ -1139,6 +1137,56 @@ func TestBuilder_InitialProofGeneratedOnce(t *testing.T) {
require.NoError(t, tab.generateInitialPost(context.Background()))
}

func TestBuilder_ObtainPostForCertification(t *testing.T) {
t.Run("no POST or ATX - fail", func(t *testing.T) {
tab := newTestBuilder(t)
_, _, err := tab.obtainPostForCertification()
require.Error(t, err)
})
t.Run("initial POST available", func(t *testing.T) {
tab := newTestBuilder(t)
tab.mpostClient.EXPECT().Proof(gomock.Any(), shared.ZeroChallenge).Return(&types.Post{}, &types.PostInfo{}, nil)
require.NoError(t, tab.generateInitialPost(context.Background()))

_, _, err := tab.obtainPostForCertification()
require.NoError(t, err)
})
t.Run("initial POST unavailable but ATX exists", func(t *testing.T) {
tab := newTestBuilder(t)
commitmentAtxId := types.RandomATXID()
challenge := types.NIPostChallenge{
PublishEpoch: 2,
Sequence: 0,
PrevATXID: types.EmptyATXID,
PositioningATX: types.RandomATXID(),
CommitmentATX: &commitmentAtxId,
InitialPost: &types.Post{},
}
nipost := newNIPostWithChallenge(t, types.HexToHash32("55555"), []byte("66666"))
nipost.Post = &types.Post{
Nonce: 5,
Indices: []byte{1, 2, 3, 4},
Pow: 7,
}
nipost.PostMetadata.LabelsPerUnit = 777
atx := types.NewActivationTx(challenge, types.Address{}, nipost, 2, nil)
atx.SetEffectiveNumUnits(2)
atx.SetReceived(time.Now())
SignAndFinalizeAtx(tab.sig, atx)
vAtx, err := atx.Verify(0, 1)
require.NoError(t, err)
require.NoError(t, atxs.Add(tab.cdb, vAtx))

post, meta, err := tab.obtainPostForCertification()
require.NoError(t, err)
require.Equal(t, commitmentAtxId, meta.CommitmentATX)
require.Equal(t, uint32(2), meta.NumUnits)
require.Equal(t, tab.nodeID, meta.NodeID)
require.Equal(t, uint64(777), meta.LabelsPerUnit)
require.Equal(t, nipost.Post, post)
})
}

func TestBuilder_InitialPostIsPersisted(t *testing.T) {
tab := newTestBuilder(t, WithPoetConfig(PoetConfig{PhaseShift: layerDuration * 4}))
tab.mpostClient.EXPECT().Proof(gomock.Any(), shared.ZeroChallenge).Return(&types.Post{}, &types.PostInfo{}, nil)
Expand Down
13 changes: 11 additions & 2 deletions activation/e2e/poet_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package activation_test
import (
"bytes"
"context"
"crypto/ed25519"
"errors"
"net/url"
"testing"
Expand Down Expand Up @@ -97,7 +98,13 @@ func TestHTTPPoet(t *testing.T) {

ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c, err := NewHTTPPoetTestHarness(ctx, poetDir)

certPubKey, certPrivKey, err := ed25519.GenerateKey(nil)
r.NoError(err)

c, err := NewHTTPPoetTestHarness(ctx, poetDir, WithCertifier(&registration.CertifierConfig{
PubKey: registration.Base64Enc(certPubKey),
}))
r.NoError(err)
r.NotNil(c)

Expand Down Expand Up @@ -127,7 +134,9 @@ func TestHTTPPoet(t *testing.T) {
ch.Bytes(),
signature,
signer.NodeID(),
activation.PoetAuth{},
activation.PoetAuth{
PoetCert: &activation.PoetCert{Signature: ed25519.Sign(certPrivKey, signer.NodeID().Bytes())},
},
)
r.NoError(err)
r.NotNil(poetRound)
Expand Down
8 changes: 4 additions & 4 deletions sql/atxs/atxs.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ func CommitmentATX(db sql.Executor, nodeID types.NodeID) (id types.ATXID, err er
}

if rows, err := db.Exec(`
select commitment_atx from atxs
select commitment_atx from atxs
where pubkey = ?1 and commitment_atx is not null
order by epoch desc
limit 1;`, enc, dec); err != nil {
Expand All @@ -150,7 +150,7 @@ func GetFirstIDByNodeID(db sql.Executor, nodeID types.NodeID) (id types.ATXID, e
}

if rows, err := db.Exec(`
select id from atxs
select id from atxs
where pubkey = ?1
order by epoch asc
limit 1;`, enc, dec); err != nil {
Expand All @@ -173,7 +173,7 @@ func GetLastIDByNodeID(db sql.Executor, nodeID types.NodeID) (id types.ATXID, er
}

if rows, err := db.Exec(`
select id from atxs
select id from atxs
where pubkey = ?1
order by epoch desc, received desc
limit 1;`, enc, dec); err != nil {
Expand Down Expand Up @@ -386,7 +386,7 @@ func LatestN(db sql.Executor, n int) ([]CheckpointAtx, error) {
}

if rows, err := db.Exec(`
select id, epoch, effective_num_units, base_tick_height, tick_count, pubkey, sequence, coinbase
select id, epoch, effective_num_units, base_tick_height, tick_count, pubkey, sequence, coinbase
from (
select row_number() over (partition by pubkey order by epoch desc) RowNum,
id, epoch, effective_num_units, base_tick_height, tick_count, pubkey, sequence, coinbase from atxs
Expand Down

0 comments on commit 40a4697

Please sign in to comment.