diff --git a/watchtower/lookout/punisher.go b/watchtower/lookout/punisher.go new file mode 100644 index 00000000..f695ef6e --- /dev/null +++ b/watchtower/lookout/punisher.go @@ -0,0 +1,58 @@ +package lookout + +import ( + "github.com/btcsuite/btcd/wire" + "github.com/lightningnetwork/lnd/lnwallet" +) + +// PunisherConfig houses the resources required by the Punisher. +type PunisherConfig struct { + // PublishTx provides the ability to send a signed transaction to the + // network. + PublishTx func(*wire.MsgTx) error + + // TODO(conner) add DB tracking and spend ntfn registration to see if + // ours confirmed or not +} + +// BreachPunisher handles the responsibility of constructing and broadcasting +// justice transactions. Justice transactions are constructed from previously +// accepted state updates uploaded by the watchtower's clients. +type BreachPunisher struct { + cfg *PunisherConfig +} + +// NewBreachPunisher constructs a new BreachPunisher given a PunisherConfig. +func NewBreachPunisher(cfg *PunisherConfig) *BreachPunisher { + return &BreachPunisher{ + cfg: cfg, + } +} + +// Punish constructs a justice transaction given a JusticeDescriptor and +// publishes is it to the network. +func (p *BreachPunisher) Punish(desc *JusticeDescriptor, quit <-chan struct{}) error { + justiceTxn, err := desc.CreateJusticeTxn() + if err != nil { + log.Errorf("Unable to create justice txn for "+ + "client=%s with breach-txid=%x: %v", + desc.SessionInfo.ID, desc.BreachedCommitTx.TxHash(), err) + return err + } + + log.Infof("Publishing justice transaction txid=%x for client=%s", + justiceTxn.TxHash(), desc.SessionInfo.ID) + + err = p.cfg.PublishTx(justiceTxn) + if err != nil && err != lnwallet.ErrDoubleSpend { + log.Errorf("Unable to publish justice txn for client=%s", + "with breach-txid=%x: %v", + desc.SessionInfo.ID, desc.BreachedCommitTx.TxHash(), err) + return err + } + + // TODO(conner): register for spend and remove from db after + // confirmation + + return nil +}