sync

package
v0.0.0-...-9146c5d Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 14, 2026 License: MIT Imports: 44 Imported by: 0

README

This sync package contains the code related to negentropy (event-set-reconciliation) and using the BitTorrent / Mainline DHT for broadcast and discovery of relays.

BEP44: BitTorrent DHT Token Management

BEP44 is a BitTorrent protocol that enables posting arbitrary signed data to hashes derived from a BitTorrent public key.

How It Works

  1. DHT Key: Nestr users that supply a dht_key can declare their list of known relays (urls) to the DHT
  2. Target: The input to the DHT for BEP44 is SHA1(pubkey + salt) where the salt is optional bytes (we use empty salt)
  3. Periodic Upload: The RelayStore object periodically re-uploads the users' relay lists to the DHT, which holds it for about 2 hours
  4. Relay Retrieval: Other users can query the DHT using the dht_key to retrieve the relay list
  5. Negentropy Sync: The RelayStore object periodically tries to sync with all relays that it is aware of
  6. Sync Store: There is a sqlite db that stores info about relays for uploading to dht and syncing

For more detailed information, please refer to the official BEP44 specification.

Documentation

Index

Constants

View Source
const FrameSizeLimit = 4096
View Source
const IdSize = 32
View Source
const NegentropyProtocol = "/negentropy/1.0.0"

Variables

View Source
var HardcodedKey = KeyPair{
	PrivKey: []byte{
		0x51, 0x8d, 0x31, 0x74, 0x5e, 0x17, 0x14, 0x28,
		0xf4, 0xbc, 0x5e, 0x2c, 0x88, 0xae, 0x2f, 0x36,
		0x37, 0x7a, 0xc2, 0xf4, 0xd3, 0xe1, 0x38, 0x68,
		0xac, 0xc6, 0x9f, 0x3f, 0x88, 0x99, 0x2b, 0xdb,
		0x6b, 0x9f, 0x74, 0x78, 0x36, 0x89, 0x4f, 0xc2,
		0xc6, 0xcd, 0xbe, 0x8d, 0xce, 0x52, 0xc1, 0xaf,
		0xc1, 0xc9, 0x48, 0xb5, 0x72, 0xf0, 0xc6, 0x62,
		0x3a, 0x07, 0xcf, 0x77, 0xb5, 0xb8, 0xf8, 0x7f,
	},
	PubKey: []byte{
		0x6b, 0x9f, 0x74, 0x78, 0x36, 0x89, 0x4f, 0xc2,
		0xc6, 0xcd, 0xbe, 0x8d, 0xce, 0x52, 0xc1, 0xaf,
		0xc1, 0xc9, 0x48, 0xb5, 0x72, 0xf0, 0xc6, 0x62,
		0x3a, 0x07, 0xcf, 0x77, 0xb5, 0xb8, 0xf8, 0x7f,
	},
}

used to make targets predictable

Functions

func CheckSig

func CheckSig(relay *ws.NIP11RelayInfo) error

func CreateDHTKeyFromPrivateKey

func CreateDHTKeyFromPrivateKey(privateKey *btcec.PrivateKey) (string, error)

CreateDHTKeyFromPrivateKey creates a DHT key from a private key This is a convenience function for creating a DHT key from a btcec.PrivateKey using the same approach as GenerateDHTKey for consistency

func CreateDHTKeyFromPublicKey

func CreateDHTKeyFromPublicKey(publicKey *btcec.PublicKey) (string, error)

CreateDHTKeyFromPublicKey creates a DHT key from a public key This is a convenience function for creating a DHT key from a btcec.PublicKey

func CreateMutableTarget

func CreateMutableTarget(pubKey []byte, salt []byte) krpc.ID

CreateMutableTarget derives the target (dht-input) for a given pubKey and salt

func CreateMutableTargetFromHex

func CreateMutableTargetFromHex(hexString string) (krpc.ID, error)

CreateMutableTargetFromHex creates a mutable target from a hex string This is a convenience function for creating a target from a hex string

func DefaultDHTServer

func DefaultDHTServer() *dht.Server

func DeriveKeyFromNsec

func DeriveKeyFromNsec(nsec string) (string, error)

DeriveKeyFromNsec derives a DHT key from a user's nsec (private key) This provides a consistent way to generate DHT keys from private keys using the same approach as GenerateDHTKey for consistency

func DoGet

func DoGet(server *dht.Server, target bep44.Target, salt []byte) ([]byte, error)

DoGet retrieves a given target from the dht

func DownloadDag

func DownloadDag(root string)

func Equals

func Equals(nr *ws.NIP11RelayInfo, other *ws.NIP11RelayInfo) bool

func GenerateDHTKey

func GenerateDHTKey(privateKeyHex string) (string, error)

GenerateDHTKey generates a DHT key from a private key hex string This is the implementation that was previously in services/server/port/main.go

func GetDHTKeyForPubkey

func GetDHTKeyForPubkey(pubkey string) (string, error)

GetDHTKeyForPubkey derives a DHT key for a given public key This is useful when you only have the public key and need to find the corresponding DHT key to retrieve data

func GetScionicRoot

func GetScionicRoot(event *nostr.Event) (string, bool)

func HandleMissingNoteRequest

func HandleMissingNoteRequest(requestJSON []byte, eventStore stores.Store, relayStore *RelayStore) ([]byte, error)

HandleMissingNoteRequest processes a request for a missing note This is called when a relay receives a request for a missing note

func InitSyncDB

func InitSyncDB() (*gorm.DB, error)

Helper function to initialize database connection

func InitiateEventSync

func InitiateEventSync(stream network.Stream, filter nostr.Filter, hostId string, store stores.Store) error

func LoadEventVector

func LoadEventVector(events []*nostr.Event) (*negentropy.Vector, error)

func MarshalRelay

func MarshalRelay(nr ws.NIP11RelayInfo) ([]byte, error)

func ParseURLs

func ParseURLs(input []byte) []string

func PerformNIP11Request

func PerformNIP11Request(url string) *ws.NIP11RelayInfo

PerformNIP11Request attempts to get NIP11 info from a given url

func PutDHTUploadable

func PutDHTUploadable(db *gorm.DB, payload []byte, pubkey []byte, signature []byte) error

PutDHTUploadable adds or updates a DHTUploadable

func PutSyncAuthor

func PutSyncAuthor(db *gorm.DB, publicKey string) error

PutSyncAuthor adds or updates a SyncAuthor

func PutSyncRelay

func PutSyncRelay(db *gorm.DB, publicKey string, relayInfo interface{}) error

PutSyncRelay adds or updates a SyncRelay

func SearchForRelays

func SearchForRelays(d *dht.Server, maxRelays int, minIndex int, maxIndex int) ([]ws.NIP11RelayInfo, []int)

SearchForRelays searches salt-space for relays to sync with The target is derived from a hardcoded key (because it needs to be predictable) and an enumeration of possible salts "nostr:relay:%d" NOTE: this is not currently used outside of tests

func SendNegentropyMessage

func SendNegentropyMessage(
	hostId string,
	stream network.Stream,
	msgType string,
	filter nostr.Filter,
	msgBytes []byte,
	errMsg string,
	needIds []string,
	haveBytes []byte) error

func SetupNegentropyEventHandler

func SetupNegentropyEventHandler(h host.Host, hostId string, store stores.Store)

func SignPut

func SignPut(put *bep44.Put, privKey ed25519.PrivateKey) error

SignPut takes a bep44 put object and formats it and signs it, putting the signature in put.Sig

func SignRelayList

func SignRelayList(relayList []string, nsec string) (string, error)

SignRelayList signs a relay list with the user's private key The signature can be verified to ensure the relay list was created by the owner

func VerifyRelayList

func VerifyRelayList(relayList []string, signature string, pubkey string) (bool, error)

VerifyRelayList verifies the signature on a relay list Returns true if the signature is valid, false otherwise

Types

type DHTUploadable

type DHTUploadable struct {
	gorm.Model
	Payload   []byte
	Pubkey    []byte
	Signature []byte
}

func GetDHTUploadables

func GetDHTUploadables(db *gorm.DB) ([]DHTUploadable, error)

type KeyPair

type KeyPair struct {
	PrivKey []byte
	PubKey  []byte
}

type MissingNoteRequest

type MissingNoteRequest struct {
	EventID      string `json:"event_id"`      // ID of the missing event
	AuthorPubkey string `json:"author_pubkey"` // Pubkey of the event author
	DHTKey       string `json:"dht_key"`       // DHT key for the author's relay list
}

MissingNoteRequest represents a request to retrieve a missing note

type MissingNoteResponse

type MissingNoteResponse struct {
	Event     *nostr.Event `json:"event"`     // The retrieved event, if found
	Found     bool         `json:"found"`     // Whether the event was found
	RelayURL  string       `json:"relay_url"` // URL of the relay where the event was found
	Timestamp int64        `json:"timestamp"` // Timestamp of when the event was found
}

MissingNoteResponse represents a response to a missing note request

func RequestMissingNoteFromRelay

func RequestMissingNoteFromRelay(request *MissingNoteRequest, targetRelayURL string) (*MissingNoteResponse, error)

RequestMissingNoteFromRelay sends a request to another relay to retrieve a missing note This is used when a relay needs to request a note from another relay

func RetrieveMissingNote

func RetrieveMissingNote(eventID string, authorPubkey string, relayStore *RelayStore, eventStore stores.Store) (*MissingNoteResponse, error)

RetrieveMissingNote retrieves a missing note from relays associated with a user It uses the DHT to find the user's relay list, then queries those relays for the note

type RelayList

type RelayList struct {
	Pubkey    string   `json:"pubkey"`
	Relays    []string `json:"relays"`
	CreatedAt int64    `json:"created_at"`
	Signature string   `json:"signature,omitempty"`
}

RelayList represents a user's list of preferred relays This structure is used for storing and retrieving relay lists from the DHT

type RelayStore

type RelayStore struct {
	// contains filtered or unexported fields
}

RelayStore struct encapsulates the connection to the dht and the db where we store relay info It also handles syncing with other relays

func GetRelayStore

func GetRelayStore() *RelayStore

func NewRelayStore

func NewRelayStore(
	db *gorm.DB,
	dhtServer *dht.Server,
	host host.Host,
	eventStore stores.Store,
	uploadInterval time.Duration,
	syncInterval time.Duration,
) *RelayStore

func (*RelayStore) AddAuthor

func (rs *RelayStore) AddAuthor(authorPubkey string)

AddAuthor adds a pubkey to the relay db

func (*RelayStore) AddRelay

func (rs *RelayStore) AddRelay(relay *ws.NIP11RelayInfo)

AddRelay adds a given relay to the relay db

func (*RelayStore) AddUploadable

func (rs *RelayStore) AddUploadable(payload string, pubkey string, signature string, uploadNow bool) error

AddUploadable saves an DHTUploadable to the relay db

func (*RelayStore) DoPut

func (rs *RelayStore) DoPut(uploadable DHTUploadable) (krpc.ID, error)

DoPut takes a DHTUploadable and puts it on the DHT

func (*RelayStore) GetRelayListFromDHT

func (rs *RelayStore) GetRelayListFromDHT(dhtKey *string) ([]*ws.NIP11RelayInfo, error)

GetRelayListFromDHT takes a dhtKey and asks the DHT for any data at the corresponding target It expects this data to be in the form of relay URLs, which we can later sync to

func (*RelayStore) RetrieveRelayList

func (rs *RelayStore) RetrieveRelayList(dhtKey string) ([]string, error)

RetrieveRelayList retrieves a relay list from the DHT Returns the relay list and any error that occurred

func (*RelayStore) StoreRelayList

func (rs *RelayStore) StoreRelayList(dhtKey string, relayList []string, pubkey string, signature string) error

StoreRelayList stores a signed relay list in the DHT This extends the existing RelayStore to support relay list storage

func (*RelayStore) SyncWithRelay

func (rs *RelayStore) SyncWithRelay(relay *ws.NIP11RelayInfo, filter nostr.Filter)

SyncWithRelay will attempt to do a negentropy event sync with a relay specified by NIP11RelayInfo if the specified relay is not a hornet relay, then we do not try to sync

type SyncAuthor

type SyncAuthor struct {
	gorm.Model
	PublicKey string `gorm:"size:128;uniqueIndex"`
}

GORM models for sync / dht related structs

func GetSyncAuthors

func GetSyncAuthors(db *gorm.DB) ([]SyncAuthor, error)

type SyncRelay

type SyncRelay struct {
	gorm.Model
	PublicKey string `gorm:"size:128;uniqueIndex"`
	RelayInfo string `gorm:"type:text"`
}

func GetSyncRelays

func GetSyncRelays(db *gorm.DB) ([]SyncRelay, error)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL