Skip to content

Commit

Permalink
chain: add Announcement type and ForEachAnnouncement
Browse files Browse the repository at this point in the history
  • Loading branch information
ChrisSchinnerl committed Jan 31, 2024
1 parent 0d8f2b5 commit 842e1c8
Showing 1 changed file with 99 additions and 0 deletions.
99 changes: 99 additions & 0 deletions chain/announcements.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package chain

import (
"bytes"

"go.sia.tech/core/types"
)

// AnnouncementSpecifier is the specifier used in the arbitrary data section
// (for v1 txns) and the attestation value (for v2 txns) when a host announces
// its net address.
const AnnouncementSpecifier = "HostAnnouncement"

type (
// Announcement represents a v1 or v2 host announcement after it has been
// validated
Announcement struct {
NetAddress string
PublicKey types.PublicKey
}

// V1Announcement represents a host announcement in v1 as stored in the
// arbitrary data section of a transaction
V1Announcement struct {
Specifier types.Specifier
NetAddress string
PublicKey types.UnlockKey
Signature types.Signature
}
)

// DecoderFrom decodes a signed announcement

Check warning on line 32 in chain/announcements.go

View workflow job for this annotation

GitHub Actions / test (ubuntu-latest, 1.20)

exported: comment on exported method V1Announcement.DecodeFrom should be of the form "DecodeFrom ..." (revive)

Check warning on line 32 in chain/announcements.go

View workflow job for this annotation

GitHub Actions / test (ubuntu-latest, 1.21)

exported: comment on exported method V1Announcement.DecodeFrom should be of the form "DecodeFrom ..." (revive)
func (a *V1Announcement) DecodeFrom(d *types.Decoder) {
a.Specifier.DecodeFrom(d)
a.NetAddress = d.ReadString()
a.PublicKey.DecodeFrom(d)
a.Signature.DecodeFrom(d)
}

// EncodeTo encodes a signed announcement
func (a V1Announcement) EncodeTo(e *types.Encoder) {
a.Specifier.EncodeTo(e)
e.WriteString(a.NetAddress)
a.PublicKey.EncodeTo(e)
a.Signature.EncodeTo(e)
}

// VerifySignature verifies the signature of the announcement using its public
// key. This can only succeed if the PublicKey is a valid ed25519 public key.
func (a V1Announcement) VerifySignature() bool {
buf := new(bytes.Buffer)
e := types.NewEncoder(buf)
a.Specifier.EncodeTo(e)
e.WriteString(a.NetAddress)
a.PublicKey.EncodeTo(e)
e.Flush()
annHash := types.HashBytes(buf.Bytes())
var pk types.PublicKey
copy(pk[:], a.PublicKey.Key)
return pk.VerifyHash(annHash, a.Signature)
}

// ForEachAnnouncement calls fn on each host announcement in a block.
func ForEachAnnouncement(b types.Block, fn func(Announcement)) {
for _, txn := range b.Transactions {
for _, arb := range txn.ArbitraryData {
// decode announcement
var ha V1Announcement
dec := types.NewBufDecoder(arb)
ha.DecodeFrom(dec)
if err := dec.Err(); err != nil {
continue
} else if ha.Specifier != types.NewSpecifier(AnnouncementSpecifier) {
continue
}
// verify signature
if !ha.VerifySignature() {
continue
}
var pk types.PublicKey
copy(pk[:], ha.PublicKey.Key)
fn(Announcement{
NetAddress: ha.NetAddress,
PublicKey: pk,
})
}
}
for _, txn := range b.V2Transactions() {
for _, att := range txn.Attestations {
if att.Key != AnnouncementSpecifier {
continue
}
fn(Announcement{
NetAddress: string(att.Value),
PublicKey: att.PublicKey,
})
}
}
}

0 comments on commit 842e1c8

Please sign in to comment.