-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chain: add Announcement type and ForEachAnnouncement
- Loading branch information
1 parent
0d8f2b5
commit 842e1c8
Showing
1 changed file
with
99 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 GitHub Actions / test (ubuntu-latest, 1.20)
|
||
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, | ||
}) | ||
} | ||
} | ||
} |